Skip to content

Commit a103e21

Browse files
committed
Diagnose CustomAttrs as needed in @abi
CustomAttr backs four different features, each of which requires a different behavior in `@abi`: • Global actors: Permitted (and permitted to vary) since they can affect mangling • Result builders: Forbidden inside an `@abi` since they have no ABI impact • Property wrappers: Forbidden both inside an `@abi` and on a decl with an `@abi` since it’s not clear how we would apply `@abi` to the auxiliary decls • Attached macros: Forbidden inside an `@abi` since an ABI-only decl has no body, accessors, members, peers, extensions, or (currently) conformances Implement these behaviors (outside of `ABIDeclChecker` since they can’t be described there). Macro-related tests are not included in this commit; they require matching swift-syntax changes which are being negotiated.
1 parent 23a7a59 commit a103e21

File tree

5 files changed

+96
-3
lines changed

5 files changed

+96
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7437,7 +7437,7 @@ ERROR(property_wrapper_effectful,none,
74377437

74387438
ERROR(property_with_wrapper_conflict_attribute,none,
74397439
"property %0 with a wrapper cannot also be "
7440-
"%select{lazy|'@NSCopying'|'@NSManaged'|weak|unowned|unmanaged}1",
7440+
"%select{lazy|'@NSCopying'|'@NSManaged'|'@abi'|weak|unowned|unmanaged}1",
74417441
(Identifier, int))
74427442
ERROR(property_wrapper_not_single_var, none,
74437443
"property wrapper can only apply to a single variable", ())
@@ -8499,6 +8499,10 @@ ERROR(attr_abi_no_default_arguments,none,
84998499
"affect the parameter's ABI",
85008500
(Decl *))
85018501
8502+
ERROR(attr_abi_no_macros,none,
8503+
"%kind0 cannot be expanded in '@abi' attribute",
8504+
(Decl *))
8505+
85028506
// These macros insert 'final', 'non-final', or nothing depending on both the
85038507
// current decl and its counterpart, such that 'non-final' is used if the
85048508
// counterpart would be described as 'final' or 'static'. They must be kept in

lib/Sema/TypeCheckAttr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4401,6 +4401,12 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
44014401
}
44024402
}
44034403

4404+
// Macros can't be attached to ABI-only decls. (If we diagnosed above,
4405+
// don't bother with this.)
4406+
if (attr->isValid() && !ABIRoleInfo(D).providesAPI()) {
4407+
diagnoseAndRemoveAttr(attr, diag::attr_abi_no_macros, macro);
4408+
}
4409+
44044410
return;
44054411
}
44064412

@@ -4482,16 +4488,25 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
44824488
// function, storage with an explicit getter, or parameter of function type.
44834489
if (nominal->getAttrs().hasAttribute<ResultBuilderAttr>()) {
44844490
ValueDecl *decl;
4491+
ValueDecl *abiRelevantDecl;
44854492
if (auto param = dyn_cast<ParamDecl>(D)) {
44864493
decl = param;
4494+
abiRelevantDecl = dyn_cast<ValueDecl>(
4495+
param->getDeclContext()->getAsDecl());
44874496
} else if (auto func = dyn_cast<FuncDecl>(D)) {
44884497
decl = func;
4498+
abiRelevantDecl = func;
44894499
} else if (auto storage = dyn_cast<AbstractStorageDecl>(D)) {
44904500
decl = storage;
4501+
abiRelevantDecl = storage;
44914502

44924503
// Check whether this is a storage declaration that is not permitted
44934504
// to have a result builder attached.
44944505
auto shouldDiagnose = [&]() -> bool {
4506+
// We'll diagnose use in @abi later.
4507+
if (!ABIRoleInfo(abiRelevantDecl).providesAPI())
4508+
return false;
4509+
44954510
// An uninitialized stored property in a struct can have a function
44964511
// builder attached.
44974512
if (auto var = dyn_cast<VarDecl>(decl)) {
@@ -4535,6 +4550,14 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
45354550
return;
45364551
}
45374552

4553+
// Result builders shouldn't be applied to an ABI-only decl because they
4554+
// have no ABI effect.
4555+
if (!ABIRoleInfo(abiRelevantDecl).providesAPI()) {
4556+
diagnoseAndRemoveAttr(attr, diag::attr_abi_forbidden_attr,
4557+
nominal->getNameStr(), /*isModifier=*/false);
4558+
return;
4559+
}
4560+
45384561
// Diagnose and ignore arguments.
45394562
if (attr->hasArgs()) {
45404563
diagnose(attr->getLocation(), diag::result_builder_arguments)

lib/Sema/TypeCheckMacros.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,12 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo,
13821382
}
13831383
}
13841384

1385+
// Macros are so spectacularly not valid in an `@abi` attribute that we cannot
1386+
// even attempt to expand them.
1387+
if (!ABIRoleInfo(attachedTo).providesAPI()) {
1388+
return nullptr;
1389+
}
1390+
13851391
ASTContext &ctx = dc->getASTContext();
13861392

13871393
auto moduleDecl = dc->getParentModule();

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,11 +484,15 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
484484
continue;
485485
}
486486

487+
auto abiRole = ABIRoleInfo(var);
488+
bool hasOrIsABI = !abiRole.providesAPI() || !abiRole.providesABI();
489+
487490
// Note: Getting the semantic attrs here would trigger a request cycle.
488491
auto attachedAttrs = var->getAttrs();
489492

490493
// Check for conflicting attributes.
491-
if (attachedAttrs.hasAttribute<LazyAttr>() ||
494+
if (hasOrIsABI ||
495+
attachedAttrs.hasAttribute<LazyAttr>() ||
492496
attachedAttrs.hasAttribute<NSCopyingAttr>() ||
493497
attachedAttrs.hasAttribute<NSManagedAttr>() ||
494498
(attachedAttrs.hasAttribute<ReferenceOwnershipAttr>() &&
@@ -501,9 +505,11 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
501505
whichKind = 1;
502506
else if (attachedAttrs.hasAttribute<NSManagedAttr>())
503507
whichKind = 2;
508+
else if (hasOrIsABI)
509+
whichKind = 3;
504510
else {
505511
auto attr = attachedAttrs.getAttribute<ReferenceOwnershipAttr>();
506-
whichKind = 2 + static_cast<unsigned>(attr->get());
512+
whichKind = 3 + static_cast<unsigned>(attr->get());
507513
}
508514
var->diagnose(diag::property_with_wrapper_conflict_attribute,
509515
var->getName(), whichKind);

test/attr/attr_abi.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,60 @@ nonisolated func isolation17() async {}
12671267
@abi(@concurrent func isolation19() async)
12681268
nonisolated(nonsending) func isolation19() async {}
12691269
1270+
// CustomAttr for property wrapper -- banned in and with '@abi'
1271+
// Banned because we would need to design behavior for its auxiliary decls.
1272+
@propertyWrapper struct PropertyWrapper {
1273+
var wrappedValue: Int { fatalError() }
1274+
}
1275+
1276+
struct CustomAttrPropertyWrapper {
1277+
@abi(@PropertyWrapper var v1: Int) // expected-error {{property 'v1' with a wrapper cannot also be '@abi'}}
1278+
@PropertyWrapper var v1: Int // expected-error {{property 'v1' with a wrapper cannot also be '@abi'}}
1279+
1280+
@abi(@PropertyWrapper var v2: Int) // expected-error {{property 'v2' with a wrapper cannot also be '@abi'}}
1281+
var v2: Int
1282+
1283+
@abi(var v3: Int)
1284+
@PropertyWrapper var v3: Int // expected-error {{property 'v3' with a wrapper cannot also be '@abi'}}
1285+
}
1286+
1287+
// CustomAttr for attached macro -- see Macros/macro_expand_peers.swift
1288+
1289+
// CustomAttr for result builder -- banned in '@abi'
1290+
// Has no ABI impact on either a parameter or a decl.
1291+
@resultBuilder struct ResultBuilder {
1292+
static func buildBlock(_ values: Int...) -> Int { values.reduce(0, +) }
1293+
}
1294+
1295+
struct CustomAttrResultBuilder {
1296+
@abi(@ResultBuilder var v1: Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}}
1297+
@ResultBuilder var v1: Int { 0 }
1298+
1299+
@abi(@ResultBuilder var v2: Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}}
1300+
var v2: Int { 0 }
1301+
1302+
@abi(var v3: Int)
1303+
@ResultBuilder var v3: Int { 0 }
1304+
1305+
@abi(@ResultBuilder func fn11() -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}}
1306+
@ResultBuilder func fn11() -> Int { 0 }
1307+
1308+
@abi(@ResultBuilder func fn21() -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}}
1309+
func fn21() -> Int { 0 }
1310+
1311+
@abi(func fn31() -> Int)
1312+
@ResultBuilder func fn31() -> Int { 0 }
1313+
1314+
@abi(func fn12(@ResultBuilder _: () -> Int) -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{18-32=}}
1315+
func fn12(@ResultBuilder _: () -> Int) -> Int { 0 }
1316+
1317+
@abi(func fn22(@ResultBuilder _: () -> Int) -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{18-32=}}
1318+
func fn22(_: () -> Int) -> Int { 0 }
1319+
1320+
@abi(func fn32(_: () -> Int) -> Int)
1321+
func fn32(@ResultBuilder _: () -> Int) -> Int { 0 }
1322+
}
1323+
12701324
// NSCopying - see attr/attr_abi_objc.swift
12711325

12721326
// @LLDBDebuggerFunction -- banned in @abi

0 commit comments

Comments
 (0)