Skip to content

Commit 7feafbd

Browse files
authored
Merge pull request swiftlang#36177 from DougGregor/global-actor-unsafe
2 parents eedbb9d + 451e6cc commit 7feafbd

File tree

12 files changed

+115
-12
lines changed

12 files changed

+115
-12
lines changed

include/swift/AST/Attr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,7 @@ class CustomAttr final : public DeclAttribute,
16631663

16641664
unsigned hasArgLabelLocs : 1;
16651665
unsigned numArgLabels : 16;
1666+
mutable unsigned isArgUnsafeBit : 1;
16661667

16671668
CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
16681669
PatternBindingInitializer *initContext, Expr *arg,
@@ -1696,6 +1697,11 @@ class CustomAttr final : public DeclAttribute,
16961697
Expr *getArg() const { return arg; }
16971698
void setArg(Expr *newArg) { arg = newArg; }
16981699

1700+
/// Determine whether the argument is '(unsafe)', a special subexpression
1701+
/// used by global actors.
1702+
bool isArgUnsafe() const;
1703+
void setArgIsUnsafe(bool unsafe) { isArgUnsafeBit = unsafe; }
1704+
16991705
Expr *getSemanticInit() const { return semanticInit; }
17001706
void setSemanticInit(Expr *expr) { semanticInit = expr; }
17011707

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4410,7 +4410,9 @@ ERROR(global_actor_on_local_variable,none,
44104410
"local variable %0 cannot have a global actor", (DeclName))
44114411
ERROR(global_actor_on_struct_property,none,
44124412
"stored property %0 of a struct cannot have a global actor", (DeclName))
4413-
4413+
ERROR(global_actor_non_unsafe_init,none,
4414+
"global actor attribute %0 argument can only be '(unsafe)'", (Type))
4415+
44144416
ERROR(actor_isolation_multiple_attr,none,
44154417
"%0 %1 has multiple actor-isolation attributes ('%2' and '%3')",
44164418
(DescriptiveDeclKind, DeclName, StringRef, StringRef))

lib/AST/Attr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,8 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
10201020
type.print(Printer, Options);
10211021
else
10221022
attr->getTypeRepr()->print(Printer, Options);
1023+
if (attr->isArgUnsafe())
1024+
Printer << "(unsafe)";
10231025
Printer.printNamePost(PrintNameContext::Attribute);
10241026
break;
10251027
}
@@ -1933,6 +1935,7 @@ CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
19331935
assert(type);
19341936
hasArgLabelLocs = !argLabelLocs.empty();
19351937
numArgLabels = argLabels.size();
1938+
isArgUnsafeBit = false;
19361939
initializeCallArguments(argLabels, argLabelLocs);
19371940
}
19381941

@@ -1975,6 +1978,26 @@ void CustomAttr::setType(Type ty) {
19751978
typeExpr->setType(MetatypeType::get(ty));
19761979
}
19771980

1981+
bool CustomAttr::isArgUnsafe() const {
1982+
if (isArgUnsafeBit)
1983+
return true;
1984+
1985+
auto arg = getArg();
1986+
if (!arg)
1987+
return false;
1988+
1989+
if (auto parenExpr = dyn_cast<ParenExpr>(arg)) {
1990+
if (auto declRef =
1991+
dyn_cast<UnresolvedDeclRefExpr>(parenExpr->getSubExpr())) {
1992+
if (declRef->getName().isSimpleName("unsafe")) {
1993+
isArgUnsafeBit = true;
1994+
}
1995+
}
1996+
}
1997+
1998+
return isArgUnsafeBit;
1999+
}
2000+
19782001
void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
19792002
if (attr)
19802003
attr->print(out);

lib/ClangImporter/ImportDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8159,10 +8159,16 @@ void ClangImporter::Implementation::importAttributes(
81598159
// FIXME: Hard-core @MainActor and @UIActor, because we don't have a
81608160
// point at which to do name lookup for imported entities.
81618161
if (swiftAttr->getAttribute() == "@MainActor" ||
8162+
swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
81628163
swiftAttr->getAttribute() == "@UIActor") {
8164+
bool isUnsafe = swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
8165+
!C.LangOpts.isSwiftVersionAtLeast(6);
81638166
if (Type mainActorType = getMainActorType()) {
81648167
auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext);
81658168
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr);
8169+
attr->setArgIsUnsafe(isUnsafe);
8170+
if (isUnsafe)
8171+
attr->setImplicit();
81668172
MappedDecl->getAttrs().add(attr);
81678173
}
81688174

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,20 @@ static Optional<ActorIsolation> getIsolationFromAttributes(
20162016
if (!globalActorType || globalActorType->hasError())
20172017
return ActorIsolation::forUnspecified();
20182018

2019+
// Handle @<global attribute type>(unsafe).
2020+
bool isUnsafe = globalActorAttr->first->isArgUnsafe();
2021+
if (globalActorAttr->first->getArg() && !isUnsafe) {
2022+
ctx.Diags.diagnose(
2023+
globalActorAttr->first->getLocation(),
2024+
diag::global_actor_non_unsafe_init, globalActorType);
2025+
}
2026+
2027+
// TODO: Model as unsafe from the actor-isolation perspective, which
2028+
// disables all checking. We probably want to model this as a separate kind
2029+
// of actor isolation to emit warnings.
2030+
if (isUnsafe)
2031+
return ActorIsolation::forIndependent(ActorIndependentKind::Unsafe);
2032+
20192033
return ActorIsolation::forGlobalActor(
20202034
globalActorType->mapTypeOutOfContext());
20212035
}
@@ -2287,6 +2301,12 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
22872301
if (isolation == overriddenIsolation)
22882302
return;
22892303

2304+
// If the overridden declaration is @actorIndependent(unsafe) and the
2305+
// overriding declaration has been placed in a global actor, allow it.
2306+
if (overriddenIsolation.getKind() == ActorIsolation::IndependentUnsafe &&
2307+
isolation.getKind() == ActorIsolation::GlobalActor)
2308+
return;
2309+
22902310
// If the overridden declaration is from Objective-C with no actor annotation,
22912311
// and the overriding declaration has been placed in a global actor, allow it.
22922312
if (overridden->hasClangNode() && !overriddenIsolation &&

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2777,8 +2777,11 @@ bool ConformanceChecker::checkActorIsolation(
27772777
break;
27782778
}
27792779

2780-
case ActorIsolation::Independent:
27812780
case ActorIsolation::IndependentUnsafe:
2781+
// The requirement is explicitly unsafe; allow it.
2782+
return false;
2783+
2784+
case ActorIsolation::Independent:
27822785
case ActorIsolation::Unspecified:
27832786
break;
27842787
}

lib/Serialization/Deserialization.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,9 +4396,10 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
43964396

43974397
case decls_block::Custom_DECL_ATTR: {
43984398
bool isImplicit;
4399+
bool isArgUnsafe;
43994400
TypeID typeID;
44004401
serialization::decls_block::CustomDeclAttrLayout::readRecord(
4401-
scratch, isImplicit, typeID);
4402+
scratch, isImplicit, typeID, isArgUnsafe);
44024403

44034404
Expected<Type> deserialized = MF.getTypeChecked(typeID);
44044405
if (!deserialized) {
@@ -4412,7 +4413,9 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() {
44124413
return deserialized.takeError();
44134414
} else {
44144415
auto *TE = TypeExpr::createImplicit(deserialized.get(), ctx);
4415-
Attr = CustomAttr::create(ctx, SourceLoc(), TE, isImplicit);
4416+
auto custom = CustomAttr::create(ctx, SourceLoc(), TE, isImplicit);
4417+
custom->setArgIsUnsafe(isArgUnsafe);
4418+
Attr = custom;
44164419
}
44174420
break;
44184421
}

lib/Serialization/ModuleFormat.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 599; // has-async-alternative
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 600; // custom attr (unsafe)
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -1943,9 +1943,9 @@ namespace decls_block {
19431943
using CustomDeclAttrLayout = BCRecordLayout<
19441944
Custom_DECL_ATTR,
19451945
BCFixed<1>, // implicit flag
1946-
TypeIDField // type referenced by this custom attribute
1946+
TypeIDField, // type referenced by this custom attribute
1947+
BCFixed<1> // is the argument (unsafe)
19471948
>;
1948-
19491949
}
19501950

19511951
/// Returns the encoding kind for the given decl.

lib/Serialization/Serialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2532,7 +2532,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
25322532
auto theAttr = cast<CustomAttr>(DA);
25332533
CustomDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
25342534
theAttr->isImplicit(),
2535-
S.addTypeRef(theAttr->getType()));
2535+
S.addTypeRef(theAttr->getType()),
2536+
theAttr->isArgUnsafe());
25362537
return;
25372538
}
25382539

test/ClangImporter/objc_async.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func testSlowServerOldSchool(slowServer: SlowServer) {
7777
func globalAsync() async { }
7878

7979
actor MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
80-
func syncMethod() { } // expected-note 2{{calls to instance method 'syncMethod()' from outside of its actor context are implicitly asynchronous}}
80+
func syncMethod() { } // expected-note {{calls to instance method 'syncMethod()' from outside of its actor context are implicitly asynchronous}}
8181

8282
func independentMethod() {
8383
syncMethod() // expected-error{{ctor-isolated instance method 'syncMethod()' can not be referenced from an '@actorIndependent' context}}
@@ -88,7 +88,7 @@ actor MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
8888
}
8989

9090
func mainActorMethod() {
91-
syncMethod() // expected-error{{actor-isolated instance method 'syncMethod()' can not be referenced from context of global actor 'MainActor'}}
91+
syncMethod()
9292
}
9393

9494
func uiActorMethod() { }

0 commit comments

Comments
 (0)