Skip to content

Commit da57cc4

Browse files
committed
Type check @abi for compatibility
This commit compares the decl inside the `@abi` attribute to the decl it’s attached to, diagnosing ABI-incompatible differences or attributes that don’t need to be specified. It includes logic which ensures that some of the fundamental properties of a declaration, such as its availability, access control, and @objc-ness, are shared between an ABI-only declaration and its counterpart. (Specifically, the ABI-only declaration delegates the computation to its counterpart.) This allows these attributes to be omitted from the `@abi` attribute instead of forcing developers to repeat themselves.
1 parent 828e2d1 commit da57cc4

35 files changed

+4008
-292
lines changed

include/swift/AST/Attr.h

Lines changed: 250 additions & 0 deletions
Large diffs are not rendered by default.

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
10501050
/// from source code.
10511051
void attachParsedAttrs(DeclAttributes attrs);
10521052

1053+
/// Retrieve the custom name in the \c @objc attribute, if present.
1054+
std::optional<ObjCSelector>
1055+
getExplicitObjCName(bool allowInvalid = false) const;
1056+
10531057
/// True if this declaration provides an implementation for an imported
10541058
/// Objective-C declaration. This implies various restrictions and special
10551059
/// behaviors for it and, if it's an extension, its members.

include/swift/AST/DeclAttr.def

Lines changed: 156 additions & 155 deletions
Large diffs are not rendered by default.

include/swift/AST/DiagnosticsSema.def

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8276,16 +8276,16 @@ ERROR(attr_abi_mismatched_kind,none,
82768276

82778277
ERROR(attr_abi_mismatched_arity,none,
82788278
"cannot give %kind0 the ABI of a %kindonly0 with a different number of "
8279-
"low-level parameters",
8280-
(ValueDecl *))
8279+
"%select{|generic }1parameters",
8280+
(Decl *, /*genericParams=*/bool))
82818281

82828282
ERROR(attr_abi_mismatched_throws,none,
82838283
"cannot give %0 the ABI of a %kindonly0 which %select{cannot|can}1 throw",
8284-
(ValueDecl *, /*abiCanThrow=*/bool))
8284+
(Decl *, /*abiCanThrow=*/bool))
82858285

82868286
ERROR(attr_abi_mismatched_async,none,
82878287
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
8288-
(ValueDecl *, /*abiIsAsync=*/bool))
8288+
(Decl *, /*abiIsAsync=*/bool))
82898289

82908290
ERROR(attr_abi_mismatched_pbd_size,none,
82918291
"cannot give pattern binding the ABI of a binding with "
@@ -8294,13 +8294,86 @@ ERROR(attr_abi_mismatched_pbd_size,none,
82948294

82958295
ERROR(attr_abi_mismatched_var,none,
82968296
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
8297-
(ValueDecl *, /*isABI=*/bool))
8297+
(Decl *, /*isABI=*/bool))
82988298

82998299
ERROR(attr_abi_incompatible_with_silgen_name,none,
83008300
"cannot use '@_silgen_name' and '@abi' on the same %0 because they serve "
83018301
"the same purpose",
83028302
(DescriptiveDeclKind))
83038303

8304+
ERROR(attr_abi_missing_attr,none,
8305+
"missing '%0' %select{attribute|modifier}1 in '@abi'",
8306+
(StringRef, bool))
8307+
ERROR(attr_abi_extra_attr,none,
8308+
"extra %select{|implicit }2'%0' %select{attribute|modifier}1 in '@abi'",
8309+
(StringRef, bool, /*isImplicit=*/bool))
8310+
ERROR(attr_abi_forbidden_attr,none,
8311+
"unused '%0' %select{attribute|modifier}1 in '@abi'",
8312+
(StringRef, bool))
8313+
REMARK(abi_attr_inferred_attribute,none,
8314+
"inferred '%0' in '@abi' to match %select{attribute|modifier}1 on API",
8315+
(StringRef, bool))
8316+
8317+
ERROR(attr_abi_mismatched_attr,none,
8318+
"'%0' %select{attribute|modifier}1 in '@abi' should match '%2'",
8319+
(StringRef, bool, StringRef))
8320+
NOTE(attr_abi_matching_attr_here,none,
8321+
"%select{should match|matches}0 %select{attribute|modifier}1 "
8322+
"%select{|implicitly added }2here",
8323+
(/*matches=*/bool, /*isModifier=*/bool, /*isImplicit=*/bool))
8324+
8325+
ERROR(attr_abi_mismatched_type,none,
8326+
"type %0 in '@abi' should match %1",
8327+
(Type, Type))
8328+
NOTE(attr_abi_should_match_type_here,none,
8329+
"should match type here", ())
8330+
8331+
ERROR(attr_abi_mismatched_generic_signature,none,
8332+
"generic signature '%0' in '@abi' is not compatible with '%1'",
8333+
(StringRef, StringRef))
8334+
ERROR(attr_abi_missing_generic_signature,none,
8335+
"declaration in '@abi' should have generic signature compatible with "
8336+
"'%0'",
8337+
(StringRef))
8338+
ERROR(attr_abi_extra_generic_signature,none,
8339+
"declaration in '@abi' should not have generic signature because %0 "
8340+
"is not generic",
8341+
(Decl *))
8342+
8343+
ERROR(attr_abi_mismatched_param_modifier,none,
8344+
"%select{default |}0%3 %select{attribute|modifier}2 "
8345+
"%select{|'%0' }0in '@abi' is not compatible with %select{default|'%1'}1",
8346+
(StringRef, StringRef, /*isModifier=*/bool, DescriptiveDeclKind))
8347+
ERROR(attr_abi_no_default_arguments,none,
8348+
"%kind0 in '@abi' should not have a default argument; it does not "
8349+
"affect the parameter's ABI",
8350+
(Decl *))
8351+
8352+
// These macros insert 'final', 'non-final', or nothing depending on both the
8353+
// current decl and its counterpart, such that 'non-final' is used if the
8354+
// counterpart would be described as 'final' or 'static'. They must be kept in
8355+
// sync with `StaticnessAndFinality`.
8356+
#define NONFINAL_OR_NOTHING(COUNTERPART) \
8357+
"%select{||non-final |non-final |non-final |%error}" #COUNTERPART
8358+
#define FINAL_OR_NONFINAL_OR_NOTHING(CURRENT, COUNTERPART, FINAL_OK) \
8359+
"%select{|%select{" NONFINAL_OR_NOTHING(COUNTERPART) \
8360+
"|" NONFINAL_OR_NOTHING(COUNTERPART) \
8361+
"|final |final ||%error}" #CURRENT "}" #FINAL_OK
8362+
8363+
ERROR(attr_abi_static_final_mismatch,none,
8364+
FINAL_OR_NONFINAL_OR_NOTHING(0, 2, 4) "%kind1 in '@abi' should be "
8365+
FINAL_OR_NONFINAL_OR_NOTHING(2, 0, 4) "%kindonly3 to ensure ABI "
8366+
"compatibility",
8367+
(uint8_t, Decl *, uint8_t, Decl *, /*isClass=*/bool))
8368+
8369+
#undef NONFINAL_OR_NOTHING
8370+
#undef FINAL_OR_NONFINAL_OR_NOTHING
8371+
8372+
ERROR(attr_abi_failable_mismatch,none,
8373+
"cannot give %select{non-failable|failable}1 %kind0 the ABI of a "
8374+
"%select{non-failable|failable}2 %kindonly0",
8375+
(Decl *, bool, bool))
8376+
83048377
//===----------------------------------------------------------------------===//
83058378
// MARK: Isolated conformances
83068379
//===----------------------------------------------------------------------===//

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ namespace swift {
263263
/// Emit a remark on early exit in explicit interface build
264264
bool EnableSkipExplicitInterfaceModuleBuildRemarks = false;
265265

266+
/// Emit a remark when \c \@abi infers an attribute or modifier.
267+
bool EnableABIInferenceRemarks = false;
268+
266269
///
267270
/// Support for alternate usage modes
268271
///

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,10 @@ def remark_module_serialization : Flag<["-"], "Rmodule-serialization">,
468468
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
469469
HelpText<"Emit remarks about module serialization">;
470470

471+
def remark_abi_inference : Flag<["-"], "Rabi-inference">,
472+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
473+
HelpText<"Emit a remark when an '@abi' attribute adds an attribute or modifier to the ABI declaration based on its presence in the API">;
474+
471475
def emit_tbd : Flag<["-"], "emit-tbd">,
472476
HelpText<"Emit a TBD file">,
473477
Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput]>;

lib/AST/ASTMangler.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,11 +1128,9 @@ getOverriddenSwiftProtocolObjCName(const ValueDecl *decl,
11281128
return std::nullopt;
11291129

11301130
// If there is an 'objc' attribute with a name, use that name.
1131-
if (auto objc = proto->getAttrs().getAttribute<ObjCAttr>()) {
1132-
if (auto name = objc->getName()) {
1133-
llvm::SmallString<4> buffer;
1134-
return std::string(name->getString(buffer));
1135-
}
1131+
if (auto objcName = proto->getExplicitObjCName()) {
1132+
llvm::SmallString<4> buffer;
1133+
return std::string(objcName->getString(buffer));
11361134
}
11371135

11381136
return std::nullopt;

lib/AST/AccessRequests.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ AccessLevel
4343
AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
4444
assert(!D->hasAccess());
4545

46+
// ABI decls share the access level of their API decl.
47+
auto abiRole = ABIRoleInfo(D);
48+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
49+
return abiRole.getCounterpart()->getFormalAccess();
50+
4651
// Check if the decl has an explicit access control attribute.
4752
if (auto *AA = D->getAttrs().getAttribute<AccessControlAttr>())
4853
return AA->getAccess();
@@ -201,6 +206,12 @@ AccessLevel
201206
SetterAccessLevelRequest::evaluate(Evaluator &evaluator,
202207
AbstractStorageDecl *ASD) const {
203208
assert(!ASD->Accessors.getInt().hasValue());
209+
210+
// ABI decls share the access level of their API decl.
211+
auto abiRole = ABIRoleInfo(ASD);
212+
if (!abiRole.providesAPI() && abiRole.getCounterpart())
213+
return abiRole.getCounterpart()->getSetterFormalAccess();
214+
204215
if (auto *SAA = ASD->getAttrs().getAttribute<SetterAccessAttr>())
205216
return SAA->getAccess();
206217

0 commit comments

Comments
 (0)