Skip to content

🌸 More @abi checking + Finish implementing @abi (SE-0476) #81393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 9, 2025
11 changes: 2 additions & 9 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,21 +380,14 @@ class DeclAttribute : public AttributeBase {
/// valid if they match.
EquivalentInABIAttr = 1ull << 18,

/// Attribute can be used in an \c \@abi attribute, but must match
/// equivalent on API decl; if omitted, API decl's attribute will be
/// cloned. Use where you would want to use \c EquivalentInABIAttr but
/// repeating the attribute is judged too burdensome.
InferredInABIAttr = 1ull << 19,

/// Use for attributes which are \em only valid on declarations that cannot
/// have an \c @abi attribute, such as \c ImportDecl .
UnreachableInABIAttr = 1ull << 20,
UnreachableInABIAttr = 1ull << 19,
};

enum : uint64_t {
InABIAttrMask = ForbiddenInABIAttr | UnconstrainedInABIAttr
| EquivalentInABIAttr | InferredInABIAttr
| UnreachableInABIAttr
| EquivalentInABIAttr | UnreachableInABIAttr
};

LLVM_READNONE
Expand Down
13 changes: 6 additions & 7 deletions include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ SIMPLE_DECL_ATTR(NSManaged, NSManaged,

CONTEXTUAL_SIMPLE_DECL_ATTR(lazy, Lazy,
OnVar,
DeclModifier | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
DeclModifier | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | UnconstrainedInABIAttr,
16)

SIMPLE_DECL_ATTR(LLDBDebuggerFunction, LLDBDebuggerFunction,
Expand All @@ -163,7 +163,7 @@ SIMPLE_DECL_ATTR(unsafe_no_objc_tagged_pointer, UnsafeNoObjCTaggedPointer,

DECL_ATTR(inline, Inline,
OnVar | OnSubscript | OnAbstractFunction,
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
20)

DECL_ATTR(_semantics, Semantics,
Expand Down Expand Up @@ -193,7 +193,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(postfix, Postfix,

SIMPLE_DECL_ATTR(_transparent, Transparent,
OnFunc | OnAccessor | OnConstructor | OnVar | OnDestructor,
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
26)

SIMPLE_DECL_ATTR(requires_stored_property_inits, RequiresStoredPropertyInits,
Expand All @@ -216,7 +216,7 @@ SIMPLE_DECL_ATTR(_fixed_layout, FixedLayout,

SIMPLE_DECL_ATTR(inlinable, Inlinable,
OnVar | OnSubscript | OnAbstractFunction,
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
32)

DECL_ATTR(_specialize, Specialize,
Expand Down Expand Up @@ -455,7 +455,7 @@ DECL_ATTR(_dynamicReplacement, DynamicReplacement,

SIMPLE_DECL_ATTR(_borrowed, Borrowed,
OnVar | OnSubscript,
UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
81)

DECL_ATTR(_private, PrivateImport,
Expand All @@ -465,7 +465,7 @@ DECL_ATTR(_private, PrivateImport,

SIMPLE_DECL_ATTR(_alwaysEmitIntoClient, AlwaysEmitIntoClient,
OnVar | OnSubscript | OnAbstractFunction,
UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr,
UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
83)

SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly,
Expand Down Expand Up @@ -860,7 +860,6 @@ DECL_ATTR(abi, ABI,
OnConstructor | OnFunc | OnSubscript | OnVar,
LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
165)
DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute)

// Unused '166': Used to be `@execution(caller | concurrent)` replaced with `@concurrent` and `nonisolated(nonsending)`

Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,11 @@ ERROR(attr_unsupported_on_target, none,
ERROR(attr_name_unsupported_on_target, none,
"attribute '%0' is unsupported on target '%1'", (StringRef, StringRef))

// abi attribute
ERROR(attr_abi_incompatible_kind,none,
"cannot use %0 in '@abi'",
(DescriptiveDeclKind))

// availability
ERROR(attr_availability_platform,none,
"expected platform name or '*' for '%0' attribute", (StringRef))
Expand Down
24 changes: 12 additions & 12 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7437,7 +7437,7 @@ ERROR(property_wrapper_effectful,none,

ERROR(property_with_wrapper_conflict_attribute,none,
"property %0 with a wrapper cannot also be "
"%select{lazy|'@NSCopying'|'@NSManaged'|weak|unowned|unmanaged}1",
"%select{lazy|'@NSCopying'|'@NSManaged'|'@abi'|weak|unowned|unmanaged}1",
(Identifier, int))
ERROR(property_wrapper_not_single_var, none,
"property wrapper can only apply to a single variable", ())
Expand Down Expand Up @@ -8434,14 +8434,10 @@ ERROR(attr_abi_mismatched_async,none,
"cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0",
(Decl *, /*abiIsAsync=*/bool))

ERROR(attr_abi_mismatched_pbd_size,none,
"cannot give pattern binding the ABI of a binding with "
"%select{more|fewer}0 patterns",
(/*abiHasExtra=*/bool))

ERROR(attr_abi_mismatched_var,none,
"no match for %select{%kind0 in the ABI|ABI %kind0}1",
(Decl *, /*isABI=*/bool))
ERROR(attr_abi_multiple_vars,none,
"'abi' attribute can only be applied to a single %0; declare each "
"%0 separately",
(DescriptiveDeclKind))

ERROR(attr_abi_incompatible_with_silgen_name,none,
"cannot use '@_silgen_name' and '@abi' on the same %0 because they serve "
Expand All @@ -8457,9 +8453,6 @@ ERROR(attr_abi_extra_attr,none,
ERROR(attr_abi_forbidden_attr,none,
"unused '%0' %select{attribute|modifier}1 in '@abi'",
(StringRef, bool))
REMARK(abi_attr_inferred_attribute,none,
"inferred '%0' in '@abi' to match %select{attribute|modifier}1 on API",
(StringRef, bool))

ERROR(attr_abi_mismatched_attr,none,
"'%0' %select{attribute|modifier}1 in '@abi' should match '%2'",
Expand Down Expand Up @@ -8499,6 +8492,13 @@ ERROR(attr_abi_no_default_arguments,none,
"affect the parameter's ABI",
(Decl *))

ERROR(attr_abi_no_macros,none,
"%kind0 cannot be expanded in '@abi' attribute",
(Decl *))
ERROR(attr_abi_no_lazy,none,
"'lazy' is not compatible with '@abi' attribute",
())

// These macros insert 'final', 'non-final', or nothing depending on both the
// current decl and its counterpart, such that 'non-final' is used if the
// counterpart would be described as 'final' or 'static'. They must be kept in
Expand Down
4 changes: 1 addition & 3 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ LANGUAGE_FEATURE(IsolatedConformances, 470, "Global-actor isolated conformances"
LANGUAGE_FEATURE(AsyncExecutionBehaviorAttributes, 0, "@concurrent and nonisolated(nonsending)")
LANGUAGE_FEATURE(GeneralizedIsSameMetaTypeBuiltin, 465, "Builtin.is_same_metatype with support for noncopyable/nonescapable types")
LANGUAGE_FEATURE(ValueGenericsNameLookup, 452, "Value generics appearing as static members for namelookup")
SUPPRESSIBLE_LANGUAGE_FEATURE(ABIAttributeSE0479, 479, "@abi attribute on functions, initializers, properties, and subscripts")

// Swift 6
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
Expand Down Expand Up @@ -488,9 +489,6 @@ EXPERIMENTAL_FEATURE(CoroutineAccessorsUnwindOnCallerError, false)
EXPERIMENTAL_FEATURE(AddressableParameters, true)
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(AddressableTypes, true)

/// Allow the @abi attribute.
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ABIAttribute, true)

/// Allow custom availability domains to be defined and referenced.
EXPERIMENTAL_FEATURE(CustomAvailability, true)

Expand Down
3 changes: 0 additions & 3 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,6 @@ namespace swift {
/// Emit a remark on early exit in explicit interface build
bool EnableSkipExplicitInterfaceModuleBuildRemarks = false;

/// Emit a remark when \c \@abi infers an attribute or modifier.
bool EnableABIInferenceRemarks = false;

///
/// Support for alternate usage modes
///
Expand Down
4 changes: 0 additions & 4 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,6 @@ def remark_module_serialization : Flag<["-"], "Rmodule-serialization">,
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Emit remarks about module serialization">;

def remark_abi_inference : Flag<["-"], "Rabi-inference">,
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Emit a remark when an '@abi' attribute adds an attribute or modifier to the ABI declaration based on its presence in the API">;

def emit_tbd : Flag<["-"], "emit-tbd">,
HelpText<"Emit a TBD file">,
Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput]>;
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3289,8 +3289,8 @@ suppressingFeatureCoroutineAccessors(PrintOptions &options,
}

static void
suppressingFeatureABIAttribute(PrintOptions &options,
llvm::function_ref<void()> action) {
suppressingFeatureABIAttributeSE0479(PrintOptions &options,
llvm::function_ref<void()> action) {
llvm::SaveAndRestore<bool> scope1(options.PrintSyntheticSILGenName, true);
ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::ABI);
action();
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static_assert(IsTriviallyDestructible<DeclAttributes>::value,
DeclAttribute::APIBreakingToRemove | DeclAttribute::APIStableToRemove), \
#Name " needs to specify either APIBreakingToRemove or APIStableToRemove"); \
static_assert(DeclAttribute::hasOneBehaviorFor##Id(DeclAttribute::InABIAttrMask), \
#Name " needs to specify exactly one of ForbiddenInABIAttr, UnconstrainedInABIAttr, EquivalentInABIAttr, InferredInABIAttr, or UnreachableInABIAttr");
#Name " needs to specify exactly one of ForbiddenInABIAttr, UnconstrainedInABIAttr, EquivalentInABIAttr, or UnreachableInABIAttr");
#include "swift/AST/DeclAttr.def"

#define TYPE_ATTR(_, Id) \
Expand Down
8 changes: 6 additions & 2 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ static ABIAttr *getABIAttr(Decl *decl) {
return decl->getAttrs().getAttribute<ABIAttr>();
}

static bool usesFeatureABIAttribute(Decl *decl) {
static bool usesFeatureABIAttributeSE0479(Decl *decl) {
return getABIAttr(decl) != nullptr;
}

Expand Down Expand Up @@ -700,8 +700,12 @@ FeatureSet swift::getUniqueFeaturesUsed(Decl *decl) {
// Remove all the features used by all enclosing declarations.
Decl *enclosingDecl = decl;
while (!features.empty()) {
// If we were in an @abi attribute, collect from the API counterpart.
auto abiRole = ABIRoleInfo(enclosingDecl);
if (!abiRole.providesAPI() && abiRole.getCounterpart())
enclosingDecl = abiRole.getCounterpart();
// Find the next outermost enclosing declaration.
if (auto accessor = dyn_cast<AccessorDecl>(enclosingDecl))
else if (auto accessor = dyn_cast<AccessorDecl>(enclosingDecl))
enclosingDecl = accessor->getStorage();
else
enclosingDecl = enclosingDecl->getDeclContext()->getAsDecl();
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,13 @@ void NominalTypeDecl::recordObjCMethod(AbstractFunctionDecl *method,
if (!ObjCMethodLookup && !createObjCMethodLookup())
return;

// Only record API decls.
Decl *abiRoleDecl = method;
if (auto accessor = dyn_cast<AccessorDecl>(method))
abiRoleDecl = accessor->getStorage();
if (!ABIRoleInfo(abiRoleDecl).providesAPI())
return;

// Record the method.
bool isInstanceMethod = method->isObjCInstanceMethod();
auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods;
Expand Down
1 change: 0 additions & 1 deletion lib/ASTGen/Sources/ASTGen/SourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ extension Parser.ExperimentalFeatures {
mapFeature(.NonescapableTypes, to: .nonescapableTypes)
mapFeature(.TrailingComma, to: .trailingComma)
mapFeature(.CoroutineAccessors, to: .coroutineAccessors)
mapFeature(.ABIAttribute, to: .abiAttribute)
mapFeature(.OldOwnershipOperatorSpellings, to: .oldOwnershipOperatorSpellings)
mapFeature(.KeyPathWithMethodMembers, to: .keypathWithMethodMembers)
mapFeature(.InlineArrayTypeSugar, to: .inlineArrayTypeSugar)
Expand Down
2 changes: 0 additions & 2 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1422,8 +1422,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,

Opts.EnableSkipExplicitInterfaceModuleBuildRemarks = Args.hasArg(OPT_remark_skip_explicit_interface_build);

Opts.EnableABIInferenceRemarks = Args.hasArg(OPT_remark_abi_inference);

if (Args.hasArg(OPT_experimental_skip_non_exportable_decls)) {
// Only allow -experimental-skip-non-exportable-decls if either library
// evolution is enabled (in which case the module's ABI is independent of
Expand Down
15 changes: 12 additions & 3 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3357,9 +3357,18 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
}

if (abiDecl) {
Attributes.add(new (Context) ABIAttr(abiDecl,
AtLoc, { Loc, rParenLoc },
/*implicit=*/false));
auto attr = new (Context) ABIAttr(abiDecl, AtLoc, { Loc, rParenLoc },
/*implicit=*/false);

// Diagnose syntactically invalid abiDecl kind here to match behavior of
// Swift parser.
if (!attr->canAppearOnDecl(abiDecl) && !isa<PatternBindingDecl>(abiDecl)){
diagnose(abiDecl->getLoc(), diag::attr_abi_incompatible_kind,
abiDecl->getDescriptiveKind());
attr->setInvalid();
}

Attributes.add(attr);
}

break;
Expand Down
19 changes: 16 additions & 3 deletions lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,9 @@ SerializedKind_t SILDeclRef::getSerializedKind() const {

auto *d = getDecl();

ASSERT(ABIRoleInfo(d).providesAPI()
&& "should not get serialization info from ABI-only decl");

// Default and property wrapper argument generators are serialized if the
// containing declaration is public.
if (isDefaultArgGenerator() || (isPropertyWrapperBackingInitializer() &&
Expand Down Expand Up @@ -1021,6 +1024,9 @@ bool SILDeclRef::isNoinline() const {
return false;

auto *decl = getDecl();
ASSERT(ABIRoleInfo(decl).providesAPI()
&& "should not get inline attr from ABI-only decl");

if (auto *attr = decl->getAttrs().getAttribute<InlineAttr>())
if (attr->getKind() == InlineKind::Never)
return true;
Expand Down Expand Up @@ -1051,6 +1057,9 @@ bool SILDeclRef::isAlwaysInline() const {
return false;
}

ASSERT(ABIRoleInfo(decl).providesAPI()
&& "should not get inline attr from ABI-only decl");

if (auto attr = decl->getAttrs().getAttribute<InlineAttr>())
if (attr->getKind() == InlineKind::Always)
return true;
Expand All @@ -1070,6 +1079,10 @@ bool SILDeclRef::isBackDeployed() const {
return false;

auto *decl = getDecl();

ASSERT(ABIRoleInfo(decl).providesAPI()
&& "should not get backDeployed from ABI-only decl");

if (auto afd = dyn_cast<AbstractFunctionDecl>(decl))
return afd->isBackDeployed(getASTContext());

Expand Down Expand Up @@ -1198,6 +1211,9 @@ static std::string mangleClangDecl(Decl *decl, bool isForeign) {
}

std::string SILDeclRef::mangle(ManglingKind MKind) const {
ASSERT(!hasDecl() || ABIRoleInfo(getDecl()).providesAPI()
&& "SILDeclRef mangling ABI decl directly?");

using namespace Mangle;
ASTMangler mangler(getASTContext());

Expand Down Expand Up @@ -1268,9 +1284,6 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
if (auto *ACE = getAbstractClosureExpr())
return mangler.mangleClosureEntity(ACE, SKind);

ASSERT(ABIRoleInfo(getDecl()).providesAPI()
&& "SILDeclRef mangling ABI decl directly?");

// As a special case, functions can have manually mangled names.
// Use the SILGen name only for the original non-thunked, non-curried entry
// point.
Expand Down
Loading