@@ -198,7 +198,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
198198 TypeChecker::checkDeclABIAttribute (D, attr);
199199 }
200200
201- void visitExecutionAttr (ExecutionAttr *attr) {
201+ void checkExecutionBehaviorAttribute (DeclAttribute *attr) {
202202 auto *const decl = cast<ValueDecl>(D);
203203
204204 auto *const storage = dyn_cast<AbstractStorageDecl>(decl);
@@ -258,6 +258,22 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
258258 }
259259 }
260260
261+ void visitExecutionAttr (ExecutionAttr *attr) {
262+ checkExecutionBehaviorAttribute (attr);
263+
264+ if (auto *concurrentAttr = D->getAttrs ().getAttribute <ConcurrentAttr>())
265+ diagnoseAndRemoveAttr (attr, diag::actor_isolation_multiple_attr_2, D,
266+ attr, concurrentAttr);
267+ }
268+
269+ void visitConcurrentAttr (ConcurrentAttr *attr) {
270+ checkExecutionBehaviorAttribute (attr);
271+
272+ if (auto *executionAttr = D->getAttrs ().getAttribute <ExecutionAttr>())
273+ diagnoseAndRemoveAttr (attr, diag::actor_isolation_multiple_attr_2, D,
274+ attr, executionAttr);
275+ }
276+
261277 void visitAlignmentAttr (AlignmentAttr *attr) {
262278 // Alignment must be a power of two.
263279 auto value = attr->getValue ();
@@ -4316,6 +4332,7 @@ static void checkGlobalActorAttr(
43164332 auto isolatedAttr = decl->getAttrs ().getAttribute <IsolatedAttr>();
43174333 auto nonisolatedAttr = decl->getAttrs ().getAttribute <NonisolatedAttr>();
43184334 auto executionAttr = decl->getAttrs ().getAttribute <ExecutionAttr>();
4335+ auto concurrentAttr = decl->getAttrs ().getAttribute <ConcurrentAttr>();
43194336
43204337 llvm::SmallVector<const DeclAttribute *, 2 > attributes;
43214338
@@ -4330,7 +4347,9 @@ static void checkGlobalActorAttr(
43304347 if (executionAttr) {
43314348 attributes.push_back (executionAttr);
43324349 }
4333-
4350+ if (concurrentAttr) {
4351+ attributes.push_back (concurrentAttr);
4352+ }
43344353 if (attributes.size () == 1 )
43354354 return ;
43364355
@@ -8145,13 +8164,13 @@ class ClosureAttributeChecker
81458164 // Nothing else to check.
81468165 }
81478166
8148- void visitExecutionAttr (ExecutionAttr *attr) {
8167+ void checkExecutionBehaviorAttribute (DeclAttribute *attr) {
81498168 if (!ctx.LangOpts .hasFeature (Feature::ExecutionAttribute)) {
81508169 visitDeclAttribute (attr);
81518170 return ;
81528171 }
81538172
8154- // `@ execution(...)` implies `async`.
8173+ // execution behavior attribute implies `async`.
81558174 if (closure->hasExplicitResultType () &&
81568175 closure->getAsyncLoc ().isInvalid ()) {
81578176 ctx.Diags
@@ -8184,6 +8203,14 @@ class ClosureAttributeChecker
81848203 }
81858204 }
81868205
8206+ void visitExecutionAttr (ExecutionAttr *attr) {
8207+ checkExecutionBehaviorAttribute (attr);
8208+ }
8209+
8210+ void visitConcurrentAttr (ConcurrentAttr *attr) {
8211+ checkExecutionBehaviorAttribute (attr);
8212+ }
8213+
81878214 void visitNonisolatedAttr (NonisolatedAttr *attr) {
81888215 if (attr->isUnsafe () ||
81898216 !ctx.LangOpts .hasFeature (Feature::ClosureIsolation)) {
0 commit comments