diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index e7a3b9d88353d..d7f3eb1c7f7d0 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -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 diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 54f25db2a931c..2c428aa9586fc 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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)` diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 76e73f3e16111..12a2af4b50694 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -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)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 4ef66222f1542..85179fad815bb 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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", ()) @@ -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 " @@ -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'", @@ -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 diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index bb3e216c828ca..365b9bb22ceb8 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -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) @@ -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) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 8a73b09290079..5d9cac773637b 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -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 /// diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 0f5b00ad5c07b..94910cf5d9d0b 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -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]>; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 9de5705fec62e..6535ee16e714c 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3289,8 +3289,8 @@ suppressingFeatureCoroutineAccessors(PrintOptions &options, } static void -suppressingFeatureABIAttribute(PrintOptions &options, - llvm::function_ref action) { +suppressingFeatureABIAttributeSE0479(PrintOptions &options, + llvm::function_ref action) { llvm::SaveAndRestore scope1(options.PrintSyntheticSILGenName, true); ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::ABI); action(); diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 12631530028cb..5e3f93ab8c77a 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -61,7 +61,7 @@ static_assert(IsTriviallyDestructible::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) \ diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 920a1d917a0c0..10a1b1e335d71 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -389,7 +389,7 @@ static ABIAttr *getABIAttr(Decl *decl) { return decl->getAttrs().getAttribute(); } -static bool usesFeatureABIAttribute(Decl *decl) { +static bool usesFeatureABIAttributeSE0479(Decl *decl) { return getABIAttr(decl) != nullptr; } @@ -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(enclosingDecl)) + else if (auto accessor = dyn_cast(enclosingDecl)) enclosingDecl = accessor->getStorage(); else enclosingDecl = enclosingDecl->getDeclContext()->getAsDecl(); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 1aeb3435d75bf..0b24e1f2210d8 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -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(method)) + abiRoleDecl = accessor->getStorage(); + if (!ABIRoleInfo(abiRoleDecl).providesAPI()) + return; + // Record the method. bool isInstanceMethod = method->isObjCInstanceMethod(); auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods; diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index d7692a4641607..ada0514e033a8 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -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) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3584e18b96054..922c20cf589ec 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -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 diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8c821d20b5660..c0207b15dae01 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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(abiDecl)){ + diagnose(abiDecl->getLoc(), diag::attr_abi_incompatible_kind, + abiDecl->getDescriptiveKind()); + attr->setInvalid(); + } + + Attributes.add(attr); } break; diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 134ecc7d77e8b..5c809011d2c53 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -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() && @@ -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()) if (attr->getKind() == InlineKind::Never) return true; @@ -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()) if (attr->getKind() == InlineKind::Always) return true; @@ -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(decl)) return afd->isBackDeployed(getASTContext()); @@ -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()); @@ -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. diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 46288ed8412e2..1f68e714881d0 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1094,6 +1094,11 @@ void AttributeChecker::visitLazyAttr(LazyAttr *attr) { // are already lazily initialized). if (VD->isStatic() || varDC->isModuleScopeContext()) diagnoseAndRemoveAttr(attr, diag::lazy_on_already_lazy_global); + + // 'lazy' can't be used in or with `@abi` because it has auxiliary decls. + auto abiRole = ABIRoleInfo(D); + if (!abiRole.providesABI() || !abiRole.providesAPI()) + diagnoseAndRemoveAttr(attr, diag::attr_abi_no_lazy); } bool AttributeChecker::visitAbstractAccessControlAttr( @@ -4401,6 +4406,12 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { } } + // Macros can't be attached to ABI-only decls. (If we diagnosed above, + // don't bother with this.) + if (attr->isValid() && !ABIRoleInfo(D).providesAPI()) { + diagnoseAndRemoveAttr(attr, diag::attr_abi_no_macros, macro); + } + return; } @@ -4482,16 +4493,25 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { // function, storage with an explicit getter, or parameter of function type. if (nominal->getAttrs().hasAttribute()) { ValueDecl *decl; + ValueDecl *abiRelevantDecl; if (auto param = dyn_cast(D)) { decl = param; + abiRelevantDecl = dyn_cast( + param->getDeclContext()->getAsDecl()); } else if (auto func = dyn_cast(D)) { decl = func; + abiRelevantDecl = func; } else if (auto storage = dyn_cast(D)) { decl = storage; + abiRelevantDecl = storage; // Check whether this is a storage declaration that is not permitted // to have a result builder attached. auto shouldDiagnose = [&]() -> bool { + // We'll diagnose use in @abi later. + if (!ABIRoleInfo(abiRelevantDecl).providesAPI()) + return false; + // An uninitialized stored property in a struct can have a function // builder attached. if (auto var = dyn_cast(decl)) { @@ -4535,6 +4555,14 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) { return; } + // Result builders shouldn't be applied to an ABI-only decl because they + // have no ABI effect. + if (!ABIRoleInfo(abiRelevantDecl).providesAPI()) { + diagnoseAndRemoveAttr(attr, diag::attr_abi_forbidden_attr, + nominal->getNameStr(), /*isModifier=*/false); + return; + } + // Diagnose and ignore arguments. if (attr->hasArgs()) { diagnose(attr->getLocation(), diag::result_builder_arguments) diff --git a/lib/Sema/TypeCheckAttrABI.cpp b/lib/Sema/TypeCheckAttrABI.cpp index d81c018ed7faa..2a91a575af455 100644 --- a/lib/Sema/TypeCheckAttrABI.cpp +++ b/lib/Sema/TypeCheckAttrABI.cpp @@ -881,26 +881,6 @@ class ABIDeclChecker : public ASTComparisonVisitor { return false; - case DeclAttribute::InferredInABIAttr: - if (!abi && api->canClone()) { - // Infer an identical attribute. - abi = api->clone(ctx); - abi->setImplicit(true); - abiDecl->getAttrs().add(abi); - - if (ctx.LangOpts.EnableABIInferenceRemarks) { - SmallString<64> scratch; - auto abiAttrAsString = printAttr(abi, abiDecl, scratch); - - abiDecl->diagnose(diag::abi_attr_inferred_attribute, - abiAttrAsString, api->isDeclModifier()); - noteAttrHere(api, apiDecl, /*isMatch=*/true); - } - } - - // Other than the cloning behavior, Inferred behaves like Equivalent. - LLVM_FALLTHROUGH; - case DeclAttribute::EquivalentInABIAttr: // Diagnose if API doesn't have attribute. if (!api) { @@ -1123,57 +1103,33 @@ class ABIDeclChecker : public ASTComparisonVisitor { }; void checkABIAttrPBD(PatternBindingDecl *APBD, VarDecl *VD) { - auto &diags = VD->getASTContext().Diags; auto PBD = VD->getParentPatternBinding(); - // To make sure we only diagnose this stuff once, check that VD is the first - // anchoring variable in the PBD. - bool isFirstAnchor = false; + Decl *anchorVD = nullptr; for (auto i : range(PBD->getNumPatternEntries())) { - auto anchorVD = PBD->getAnchoringVarDecl(i); - if (anchorVD) { - isFirstAnchor = (anchorVD == VD); + anchorVD = PBD->getAnchoringVarDecl(i); + if (anchorVD) break; - } } - if (!isFirstAnchor) + // To make sure we only diagnose this stuff once, check that VD is the + // first anchoring variable in the PBD. + if (anchorVD != VD) return; - // Check that the PBDs have the same number of patterns. - if (PBD->getNumPatternEntries() < APBD->getNumPatternEntries()) { - diags.diagnose(APBD->getPattern(PBD->getNumPatternEntries())->getLoc(), - diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/false); - return; - } - if (PBD->getNumPatternEntries() > APBD->getNumPatternEntries()) { - diags.diagnose(PBD->getPattern(APBD->getNumPatternEntries())->getLoc(), - diag::attr_abi_mismatched_pbd_size, /*abiHasExtra=*/true); + // In the final approved feature, we only permit single-variable patterns. + // (However, the rest of the compiler tolerates them.) + if (!PBD->getSingleVar() || !APBD->getSingleVar()) { + PBD->diagnose(diag::attr_abi_multiple_vars, + anchorVD ? anchorVD->getDescriptiveKind() + : PBD->getDescriptiveKind()); return; } - // Check that each pattern has the same number of variables. - for (auto i : range(PBD->getNumPatternEntries())) { - SmallVector VDs; - SmallVector AVDs; - - PBD->getPattern(i)->collectVariables(VDs); - APBD->getPattern(i)->collectVariables(AVDs); - - if (VDs.size() < AVDs.size()) { - for (auto AVD : drop_begin(AVDs, VDs.size())) { - AVD->diagnose(diag::attr_abi_mismatched_var, - AVD, /*isABI=*/true); - } - } - else if (VDs.size() > AVDs.size()) { - for (auto VD : drop_begin(VDs, AVDs.size())) { - VD->diagnose(diag::attr_abi_mismatched_var, - VD, /*isABI=*/false); - } - } - } + // Check the ABI PBD--this is what checks the underlying vars. + TypeChecker::typeCheckDecl(APBD); } + } // end anonymous namespace void TypeChecker::checkDeclABIAttribute(Decl *D, ABIAttr *attr) { diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index fb7f8d6e3c75d..98864dd784247 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -618,15 +618,15 @@ static void checkGenericParams(GenericContext *ownerCtx) { /// Returns \c true if \p current and \p other are in the same source file /// \em and \c current appears before \p other in that file. static bool isBeforeInSameFile(Decl *current, Decl *other) { - if (current->getDeclContext()->getParentSourceFile() != - other->getDeclContext()->getParentSourceFile()) + if (current->getDeclContext()->getOutermostParentSourceFile() != + other->getDeclContext()->getOutermostParentSourceFile()) return false; - if (!current->getLoc().isValid()) + if (current->getLoc().isInvalid() || other->getLoc().isInvalid()) return false; return current->getASTContext().SourceMgr - .isBeforeInBuffer(current->getLoc(), other->getLoc()); + .isBefore(current->getLoc(), other->getLoc()); } template diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 305be67eb1557..2d5c237044671 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1382,6 +1382,12 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, } } + // Macros are so spectacularly not valid in an `@abi` attribute that we cannot + // even attempt to expand them. + if (!ABIRoleInfo(attachedTo).providesAPI()) { + return nullptr; + } + ASTContext &ctx = dc->getASTContext(); auto moduleDecl = dc->getParentModule(); diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 849ab5e26f27d..45879bdd056ac 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -484,11 +484,15 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, continue; } + auto abiRole = ABIRoleInfo(var); + bool hasOrIsABI = !abiRole.providesAPI() || !abiRole.providesABI(); + // Note: Getting the semantic attrs here would trigger a request cycle. auto attachedAttrs = var->getAttrs(); // Check for conflicting attributes. - if (attachedAttrs.hasAttribute() || + if (hasOrIsABI || + attachedAttrs.hasAttribute() || attachedAttrs.hasAttribute() || attachedAttrs.hasAttribute() || (attachedAttrs.hasAttribute() && @@ -501,9 +505,11 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, whichKind = 1; else if (attachedAttrs.hasAttribute()) whichKind = 2; + else if (hasOrIsABI) + whichKind = 3; else { auto attr = attachedAttrs.getAttribute(); - whichKind = 2 + static_cast(attr->get()); + whichKind = 3 + static_cast(attr->get()); } var->diagnose(diag::property_with_wrapper_conflict_attribute, var->getName(), whichKind); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 515032bd380aa..c8177979c7c78 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -849,6 +849,10 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator, OpaqueReadOwnership OpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { + auto abiRole = ABIRoleInfo(storage); + if (!abiRole.providesAPI() && abiRole.getCounterpart()) + return abiRole.getCounterpart()->getOpaqueReadOwnership(); + enum class DiagKind { BorrowedAttr, NoncopyableType @@ -3847,6 +3851,10 @@ void HasStorageRequest::cacheResult(bool hasStorage) const { StorageImplInfo StorageImplInfoRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { + auto abiRole = ABIRoleInfo(storage); + if (!abiRole.providesAPI() && abiRole.getCounterpart()) + return abiRole.getCounterpart()->getImplInfo(); + if (auto *param = dyn_cast(storage)) { return StorageImplInfo::getSimpleStored( param->isImmutableInFunctionBody() diff --git a/test/ASTGen/attrs.swift b/test/ASTGen/attrs.swift index 39c8f5379eb9c..9b9c3aba5e497 100644 --- a/test/ASTGen/attrs.swift +++ b/test/ASTGen/attrs.swift @@ -1,7 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend-dump-parse \ -// RUN: -enable-experimental-feature ABIAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -12,7 +11,6 @@ // RUN: | %sanitize-address > %t/astgen.ast // RUN: %target-swift-frontend-dump-parse \ -// RUN: -enable-experimental-feature ABIAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -26,7 +24,6 @@ // RUN: %target-typecheck-verify-swift \ // RUN: -module-abi-name ASTGen \ // RUN: -enable-experimental-feature ParserASTGen \ -// RUN: -enable-experimental-feature ABIAttribute \ // RUN: -enable-experimental-feature Extern \ // RUN: -enable-experimental-feature LifetimeDependence \ // RUN: -enable-experimental-feature RawLayout \ @@ -38,7 +35,6 @@ // REQUIRES: executable_test // REQUIRES: swift_swift_parser // REQUIRES: swift_feature_ParserASTGen -// REQUIRES: swift_feature_ABIAttribute // REQUIRES: swift_feature_Extern // REQUIRES: swift_feature_LifetimeDependence // REQUIRES: swift_feature_RawLayout diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index b7fda6f209720..a7104e38d3dc3 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -19,6 +19,11 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD_INDEPENDENT_2 | %FileCheck %s -check-prefix=KEYWORD_LAST // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD_LAST | %FileCheck %s -check-prefix=KEYWORD_LAST +// NOTE: If you want to test code completion for an experimental feature, please +// put your tests in complete_decl_attribute_feature_requirement.swift, not +// here. That file has the infrastructure to test that completions are not +// offered when the feature is disabled. + struct MyStruct {} @propertyWrapper @@ -111,7 +116,10 @@ actor MyGenericGlobalActor { // KEYWORD2-NEXT: Keyword/None: Sendable[#Func Attribute#]; name=Sendable // KEYWORD2-NEXT: Keyword/None: preconcurrency[#Func Attribute#]; name=preconcurrency // KEYWORD2-NEXT: Keyword/None: backDeployed[#Func Attribute#]; name=backDeployed -// KEYWORD2-NEXT Keyword/None: lifetime[#Func Attribute#]; name=lifetime +// KEYWORD2-NEXT: Keyword/None: lifetime[#Func Attribute#]; name=lifetime +// KEYWORD2-NEXT: Keyword/None: abi[#Func Attribute#]; name=abi{{$}} +// KEYWORD2-NEXT: Keyword/None: concurrent[#Func Attribute#]; name=concurrent +// KEYWORD2-NOT: Keyword // KEYWORD2-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // KEYWORD2-DAG: Decl[Struct]/CurrModule: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper // KEYWORD2-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyResultBuilder[#Result Builder#]; name=MyResultBuilder @@ -167,6 +175,7 @@ actor MyGenericGlobalActor { // KEYWORD5-NEXT: Keyword/None: preconcurrency[#Struct Attribute#]; name=preconcurrency @#^ON_GLOBALVAR^# var globalVar +// ON_GLOBALVAR-DAG: Keyword/None: abi[#Var Attribute#]; name=abi // ON_GLOBALVAR-DAG: Keyword/None: available[#Var Attribute#]; name=available // ON_GLOBALVAR-DAG: Keyword/None: objc[#Var Attribute#]; name=objc // ON_GLOBALVAR-DAG: Keyword/None: NSCopying[#Var Attribute#]; name=NSCopying @@ -195,6 +204,7 @@ actor MyGenericGlobalActor { struct _S { @#^ON_INIT^# init() +// ON_INIT-DAG: Keyword/None: abi[#Constructor Attribute#]; name=abi // ON_INIT-DAG: Keyword/None: available[#Constructor Attribute#]; name=available // ON_INIT-DAG: Keyword/None: objc[#Constructor Attribute#]; name=objc // ON_INIT-DAG: Keyword/None: inline[#Constructor Attribute#]; name=inline @@ -205,6 +215,7 @@ struct _S { // ON_INIT-DAG: Keyword/None: preconcurrency[#Constructor Attribute#]; name=preconcurrency @#^ON_PROPERTY^# var foo +// ON_PROPERTY-DAG: Keyword/None: abi[#Var Attribute#]; name=abi // ON_PROPERTY-DAG: Keyword/None: available[#Var Attribute#]; name=available // ON_PROPERTY-DAG: Keyword/None: objc[#Var Attribute#]; name=objc // ON_PROPERTY-DAG: Keyword/None: NSCopying[#Var Attribute#]; name=NSCopying @@ -232,8 +243,12 @@ struct _S { // ON_PROPERTY-DAG: Decl[Actor]/CurrModule/TypeRelation[Convertible]: MyGenericGlobalActor[#Global Actor#]; name=MyGenericGlobalActor // ON_PROPERTY-NOT: Decl[PrecedenceGroup] + @#^ON_SUBSCR^# subscript +// ON_SUBSCR-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi + @#^ON_METHOD^# private func foo() +// ON_METHOD-DAG: Keyword/None: abi[#Func Attribute#]; name=abi // ON_METHOD-DAG: Keyword/None: available[#Func Attribute#]; name=available // ON_METHOD-DAG: Keyword/None: objc[#Func Attribute#]; name=objc // ON_METHOD-DAG: Keyword/None: IBAction[#Func Attribute#]; name=IBAction @@ -291,6 +306,7 @@ struct _S { @#^ON_MEMBER_LAST^# +// ON_MEMBER_LAST-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi // ON_MEMBER_LAST-DAG: Keyword/None: available[#Declaration Attribute#]; name=available // ON_MEMBER_LAST-DAG: Keyword/None: objc[#Declaration Attribute#]; name=objc // ON_MEMBER_LAST-DAG: Keyword/None: dynamicCallable[#Declaration Attribute#]; name=dynamicCallable @@ -345,6 +361,8 @@ func takeClosure(_: () -> Void) { print("x") } } +// FIXME: Not valid in this position (but CompletionLookup can't tell that) +// IN_CLOSURE-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi // FIXME: We should mark MyPropertyWrapper and MyResultBuilder as Unrelated // IN_CLOSURE-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // IN_CLOSURE-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper @@ -363,6 +381,7 @@ func dummy2() {} @#^KEYWORD_LAST^# +// KEYWORD_LAST-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi // KEYWORD_LAST-DAG: Keyword/None: available[#Declaration Attribute#]; name=available{{$}} // KEYWORD_LAST-DAG: Keyword/None: freestanding[#Declaration Attribute#]; name=freestanding{{$}} // KEYWORD_LAST-DAG: Keyword/None: objc[#Declaration Attribute#]; name=objc{{$}} diff --git a/test/IDE/complete_decl_attribute_feature_requirement.swift b/test/IDE/complete_decl_attribute_feature_requirement.swift index f3d12029bc26e..461666a5e1f2f 100644 --- a/test/IDE/complete_decl_attribute_feature_requirement.swift +++ b/test/IDE/complete_decl_attribute_feature_requirement.swift @@ -3,6 +3,11 @@ // it's enabled. When a feature becomes non-experimental, move its test cases // into the normal complete_decl_attribute.swift test file. +// NOTE: There are currently no experimental features that need code completion +// testing, but this test file is being left in place for when it's needed +// again. At that time, please remove the ABIAttribute tests. +// REQUIRES: new_use_case + // REQUIRES: asserts // RUN: %batch-code-completion -filecheck-additional-suffix _DISABLED diff --git a/test/IRGen/asmname.swift b/test/IRGen/asmname.swift index 50d40110adfb7..6f1236dd4818d 100644 --- a/test/IRGen/asmname.swift +++ b/test/IRGen/asmname.swift @@ -1,9 +1,8 @@ -// RUN: %target-swift-frontend -enable-experimental-feature ABIAttribute %s -emit-ir > %t.ir +// RUN: %target-swift-frontend %s -emit-ir > %t.ir // RUN: %FileCheck --input-file %t.ir %s // RUN: %FileCheck --check-prefix NEGATIVE --input-file %t.ir %s // REQUIRES: CPU=i386 || CPU=x86_64 || CPU=arm64 -// REQUIRES: swift_feature_ABIAttribute // Non-Swift _silgen_name definitions diff --git a/test/Macros/macro_expand.swift b/test/Macros/macro_expand.swift index 4ca11c6b8335a..074fcb5a6bd54 100644 --- a/test/Macros/macro_expand.swift +++ b/test/Macros/macro_expand.swift @@ -135,6 +135,23 @@ class HasStoredPropertyClassInvalid { // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-2]]_2_33_{{.*}}AddStoredPropertyfMf_.swift:1:22: error: covariant 'Self' type cannot be referenced from a stored property initializer } +// Redeclaration checking should behave as though expansions are part of the +// source file. +struct RedeclChecking { + #varValue + + // expected-error@+1 {{invalid redeclaration of 'value'}} + var value: Int { 0 } +} + +// CHECK-DIAGS: macro_expand.swift:[[@LINE-3]]:7: error: invalid redeclaration of 'value' +// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-8]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll8varValuefMf_.swift:1:5: note: 'value' previously declared here +// CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-9]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll8varValuefMf_.swift: +// CHECK-DIAGS: var value: Int { +// CHECK-DIAGS: 1 +// CHECK-DIAGS: } +// CHECK-DIAGS: END CONTENTS OF FILE + @attached(body) public macro ThrowCancellation() = #externalMacro(module: "MacroDefinition", type: "ThrowCancellationMacro") @@ -702,6 +719,29 @@ func testPropertyWrapperMacro() { #hasPropertyWrapperParam($x: .init(wrappedValue: 0)) } +#if swift(>=1.0) && TEST_DIAGNOSTICS +// Test that macros can't be used in @abi + +struct ABIAttrWithFreestandingMacro1 { + // expected-error@+1 {{cannot use pound literal in '@abi'}} + @abi(#varValue) + #varValue + // expected-note@-1 {{in expansion of macro 'varValue' here}} +} + +struct ABIAttrWithFreestandingMacro2 { + // expected-error@+1 {{cannot use pound literal in '@abi'}} + @abi(#varValue) + var value: Int { 0 } +} + +struct ABIAttrWithFreestandingMacro3 { + @abi(var value: Int) + #varValue +} + +#endif + #if TEST_DIAGNOSTICS @freestanding(expression) macro missingMacro() = #externalMacro(module: "MacroDefinition", type: "BluhBlah") diff --git a/test/Macros/macro_expand_peers.swift b/test/Macros/macro_expand_peers.swift index 99f8febe7fe7f..dfd8a3cc0897a 100644 --- a/test/Macros/macro_expand_peers.swift +++ b/test/Macros/macro_expand_peers.swift @@ -309,3 +309,26 @@ func closuresInPeerMacroCrash() {} @trait(Trait {}) @trait(Trait {}) var closuresInPeerMacroOnVariableCrash: Int = 0 + +// Test that macros can't be used in @abi + +#if swift(>=5.3) && TEST_DIAGNOSTICS +struct ABIAttrWithAttachedMacro { + // expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}} + @abi(@addCompletionHandler func fn1() async) + @addCompletionHandler func fn1() async {} + // From diagnostics in the expansion: + // expected-note@-2 3{{in expansion of macro 'addCompletionHandler' on instance method 'fn1()' here}} + // expected-note@-4 {{'fn1()' previously declared here}} + + // expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}} + @abi(@addCompletionHandler func fn2() async) + func fn2() async {} + + @abi(func fn3() async) + @addCompletionHandler func fn3() async {} + // From diagnostics in the expansion: + // expected-note@-2 2{{in expansion of macro 'addCompletionHandler' on instance method 'fn3()' here}} + // expected-note@-4 {{'fn3()' previously declared here}} +} +#endif diff --git a/test/ModuleInterface/attrs.swift b/test/ModuleInterface/attrs.swift index 1360aae2a790f..56da19cc2e346 100644 --- a/test/ModuleInterface/attrs.swift +++ b/test/ModuleInterface/attrs.swift @@ -1,6 +1,5 @@ // RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name attrs \ -// RUN: -emit-private-module-interface-path %t.private.swiftinterface \ -// RUN: -enable-experimental-feature ABIAttribute +// RUN: -emit-private-module-interface-path %t.private.swiftinterface // RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name attrs // RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -module-name attrs @@ -8,8 +7,6 @@ // RUN: %FileCheck %s --check-prefixes CHECK,PUBLIC-CHECK --input-file %t.swiftinterface // RUN: %FileCheck %s --check-prefixes CHECK,PRIVATE-CHECK --input-file %t.private.swiftinterface -// REQUIRES: swift_feature_ABIAttribute - // CHECK: @_transparent public func glass() -> Swift.Int { return 0 }{{$}} @_transparent public func glass() -> Int { return 0 } @@ -38,7 +35,7 @@ internal func __specialize_someGenericFunction(_ t: T) -> Int { @abi(func __abi__abiAttrOnFunction(param: Int)) public func abiAttrOnFunction(param: Int) {} -// CHECK: #if {{.*}} $ABIAttribute +// CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(func __abi__abiAttrOnFunction(param: Swift.Int)) // CHECK: public func abiAttrOnFunction(param: Swift.Int) // CHECK: #else @@ -48,7 +45,7 @@ public func abiAttrOnFunction(param: Int) {} @abi(let __abi__abiAttrOnVar: Int) public var abiAttrOnVar: Int = 42 -// CHECK: #if {{.*}} $ABIAttribute +// CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(var __abi__abiAttrOnVar: Swift.Int) // CHECK: public var abiAttrOnVar: Swift.Int // CHECK: #else @@ -57,7 +54,7 @@ public var abiAttrOnVar: Int = 42 // CHECK: #endif public struct MutatingTest { - // CHECK: #if {{.*}} $ABIAttribute + // CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(mutating func abiMutFunc()) // CHECK: public mutating func abiMutFunc() // CHECK: #else @@ -68,14 +65,14 @@ public struct MutatingTest { public mutating func abiMutFunc() {} } -// PUBLIC-CHECK-NOT: #if {{.*}} $ABIAttribute +// PUBLIC-CHECK-NOT: #if {{.*}} $ABIAttributeSE0479 // PUBLIC-CHECK-NOT: @abi(func abiSpiFunc()) // PUBLIC-CHECK-NOT: public func abiSpiFunc() // PUBLIC-CHECK-NOT: #else // PUBLIC-CHECK-NOT: @_silgen_name("$s5attrs10abiSpiFuncyyF") // PUBLIC-CHECK-NOT: public func abiSpiFunc() // PUBLIC-CHECK-NOT: #endif -// PRIVATE-CHECK: #if {{.*}} $ABIAttribute +// PRIVATE-CHECK: #if {{.*}} $ABIAttributeSE0479 // PRIVATE-CHECK: @abi(func abiSpiFunc()) // PRIVATE-CHECK: public func abiSpiFunc() // PRIVATE-CHECK: #else @@ -85,6 +82,20 @@ public struct MutatingTest { @abi(func abiSpiFunc()) @_spi(spiGroup) public func abiSpiFunc() {} +// We should print feature guards outside, but not inside, an @abi attribute. +@abi(func sendingABI() -> sending Any?) +public func sendingABI() -> Any? { nil } +// CHECK: #if {{.*}} && $ABIAttributeSE0479 +// CHECK: @abi(func sendingABI() -> sending Any?) +// CHECK: public func sendingABI() -> Any? +// CHECK: #elseif {{.*}} && $SendingArgsAndResults +// CHECK: @_silgen_name("$s5attrs10sendingABIypSgyF") +// CHECK: public func sendingABI() -> Any? +// CHECK: #else +// CHECK: @_silgen_name("$s5attrs10sendingABIypSgyF") +// CHECK: public func sendingABI() -> Any? +// CHECK: #endif + @concurrent public func testExecutionConcurrent() async {} // CHECK: @concurrent public func testExecutionConcurrent() async diff --git a/test/ModuleInterface/attrs_objc.swift b/test/ModuleInterface/attrs_objc.swift index 37cb78318be05..0f8fd5b1f2ca0 100644 --- a/test/ModuleInterface/attrs_objc.swift +++ b/test/ModuleInterface/attrs_objc.swift @@ -1,19 +1,17 @@ // RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s \ -// RUN: -enable-objc-interop -module-name attrs_objc \ -// RUN: -enable-experimental-feature ABIAttribute +// RUN: -enable-objc-interop -module-name attrs_objc // RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name attrs_objc // RUN: %FileCheck %s --input-file %t.swiftinterface // REQUIRES: objc_interop -// REQUIRES: swift_feature_ABIAttribute import Foundation @objcMembers public class ObjCTest: NSObject { - // CHECK: #if {{.*}} $ABIAttribute + // CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(func abiObjCFunc()) // CHECK: @objc public func abiObjCFunc() // CHECK: #else @@ -23,7 +21,7 @@ public class ObjCTest: NSObject { @abi(func abiObjCFunc()) @objc public func abiObjCFunc() {} - // CHECK: #if {{.*}} $ABIAttribute + // CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(func abiImplicitObjCFunc()) // CHECK: @objc public func abiImplicitObjCFunc() // CHECK: #else @@ -33,7 +31,7 @@ public class ObjCTest: NSObject { @abi(func abiImplicitObjCFunc()) public func abiImplicitObjCFunc() {} - // CHECK: #if {{.*}} $ABIAttribute + // CHECK: #if {{.*}} $ABIAttributeSE0479 // CHECK: @abi(func abiIBActionFunc(_: Any)) // CHECK: @objc @IBAction @_Concurrency.MainActor @preconcurrency public func abiIBActionFunc(_: Any) // CHECK: #else diff --git a/test/attr/attr_abi.swift b/test/attr/attr_abi.swift index 96be8a8d29105..49116208b3740 100644 --- a/test/attr/attr_abi.swift +++ b/test/attr/attr_abi.swift @@ -1,6 +1,5 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern -enable-experimental-feature ABIAttribute -enable-experimental-feature AddressableParameters -enable-experimental-feature NoImplicitCopy -enable-experimental-feature SymbolLinkageMarkers -enable-experimental-feature StrictMemorySafety -enable-experimental-feature LifetimeDependence -enable-experimental-feature CImplementation -import-bridging-header %S/Inputs/attr_abi.h -parse-as-library -Rabi-inference -debugger-support +// RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern -enable-experimental-feature AddressableParameters -enable-experimental-feature NoImplicitCopy -enable-experimental-feature SymbolLinkageMarkers -enable-experimental-feature StrictMemorySafety -enable-experimental-feature LifetimeDependence -enable-experimental-feature CImplementation -import-bridging-header %S/Inputs/attr_abi.h -parse-as-library -debugger-support -// REQUIRES: swift_feature_ABIAttribute // REQUIRES: swift_feature_AddressableParameters // REQUIRES: swift_feature_CImplementation // REQUIRES: swift_feature_Extern @@ -279,17 +278,20 @@ var async11Var: Int { get async { fatalError() } } // PBD shape checking // -@abi(var x1, y1: Int) // expected-error {{cannot give pattern binding the ABI of a binding with more patterns}} -var x1: Int = 0 +@abi(var x1, y1: Int) +var x1: Int = 0 // expected-error {{'abi' attribute can only be applied to a single var; declare each var separately}} @abi(var x2: Int) -var x2 = 0, y2: Int = 0 // expected-error {{cannot give pattern binding the ABI of a binding with fewer patterns}} +var x2 = 0, y2: Int = 0 // expected-error {{'abi' attribute can only be applied to a single var; declare each var separately}} -@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int)) // expected-error {{no match for ABI var 'b3'}} -var (x3, y3): (Int, Int) = (0, 0), a3: Int = 0 +@abi(var (x3, y3): (Int, Int), (a3, b3): (Int, Int)) +var (x3, y3): (Int, Int) = (0, 0), a3: Int = 0 // expected-error {{'abi' attribute can only be applied to a single var; declare each var separately}} @abi(var (x4, y4): (Int, Int), a4: Int) -var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0) // expected-error {{no match for var 'b4' in the ABI}} +var (x4, y4): (Int, Int) = (0, 0), (a4, b4): (Int, Int) = (0, 0) // expected-error {{'abi' attribute can only be applied to a single var; declare each var separately}} + +@abi(var x5: Int) +var x5: Int = 0 // // Redeclaration diagnostics @@ -1267,6 +1269,61 @@ nonisolated func isolation17() async {} @abi(@concurrent func isolation19() async) nonisolated(nonsending) func isolation19() async {} +// CustomAttr for property wrapper -- banned in and with '@abi' +// Banned because we would need to design behavior for its auxiliary decls. +@propertyWrapper struct PropertyWrapper { + var wrappedValue: Int { fatalError() } +} + +struct CustomAttrPropertyWrapper { + @abi(@PropertyWrapper var v1: Int) // expected-error {{property 'v1' with a wrapper cannot also be '@abi'}} + @PropertyWrapper var v1: Int // expected-error {{property 'v1' with a wrapper cannot also be '@abi'}} + + @abi(@PropertyWrapper var v2: Int) // expected-error {{property 'v2' with a wrapper cannot also be '@abi'}} + var v2: Int + + @abi(var v3: Int) + @PropertyWrapper var v3: Int // expected-error {{property 'v3' with a wrapper cannot also be '@abi'}} +} + +// CustomAttr for attached macro -- see Macros/macro_expand_peers.swift +// Freestanding macro in @abi -- see Macros/macro_expand.swift + +// CustomAttr for result builder -- banned in '@abi' +// Has no ABI impact on either a parameter or a decl. +@resultBuilder struct ResultBuilder { + static func buildBlock(_ values: Int...) -> Int { values.reduce(0, +) } +} + +struct CustomAttrResultBuilder { + @abi(@ResultBuilder var v1: Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}} + @ResultBuilder var v1: Int { 0 } + + @abi(@ResultBuilder var v2: Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}} + var v2: Int { 0 } + + @abi(var v3: Int) + @ResultBuilder var v3: Int { 0 } + + @abi(@ResultBuilder func fn11() -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}} + @ResultBuilder func fn11() -> Int { 0 } + + @abi(@ResultBuilder func fn21() -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{8-22=}} + func fn21() -> Int { 0 } + + @abi(func fn31() -> Int) + @ResultBuilder func fn31() -> Int { 0 } + + @abi(func fn12(@ResultBuilder _: () -> Int) -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{18-32=}} + func fn12(@ResultBuilder _: () -> Int) -> Int { 0 } + + @abi(func fn22(@ResultBuilder _: () -> Int) -> Int) // expected-error {{unused 'ResultBuilder' attribute in '@abi'}} {{18-32=}} + func fn22(_: () -> Int) -> Int { 0 } + + @abi(func fn32(_: () -> Int) -> Int) + func fn32(@ResultBuilder _: () -> Int) -> Int { 0 } +} + // NSCopying - see attr/attr_abi_objc.swift // @LLDBDebuggerFunction -- banned in @abi @@ -1813,45 +1870,48 @@ func section2() {} @abi(func section3()) @_section("fnord") func section3() {} -// @inlinable -- automatically cloned into @abi -@abi(@inlinable func inlinable1()) +// @inlinable -- banned in @abi +// Although the inlining *does* occasionally get mangled, it's only done in the +// SpecializationManglers, which shouldn't get their serialization from an ABI +// attribute. +@abi(@inlinable func inlinable1()) // expected-error {{unused 'inlinable' attribute in '@abi'}} {{6-16=}} @inlinable func inlinable1() {} -@abi(@inlinable func inlinable2()) // expected-error {{extra 'inlinable' attribute in '@abi'}} {{6-16=}} +@abi(@inlinable func inlinable2()) // expected-error {{unused 'inlinable' attribute in '@abi'}} {{6-16=}} func inlinable2() {} -@abi(func inlinable3()) // expected-remark {{inferred '@inlinable' in '@abi' to match attribute on API}} -@inlinable func inlinable3() {} // expected-note {{matches attribute here}} +@abi(func inlinable3()) +@inlinable func inlinable3() {} -// @inline -- automatically cloned into @abi -@abi(@inline(never) func inline1()) +// @inlinable -- banned in @abi +@abi(@inline(never) func inline1()) // expected-error {{unused 'inline(never)' attribute in '@abi'}} {{6-20=}} @inline(never) func inline1() {} -@abi(@inline(never) func inline2()) // expected-error {{extra 'inline(never)' attribute in '@abi'}} {{6-20=}} +@abi(@inline(never) func inline2()) // expected-error {{unused 'inline(never)' attribute in '@abi'}} {{6-20=}} func inline2() {} -@abi(func inline3()) // expected-remark {{inferred '@inline(never)' in '@abi' to match attribute on API}} -@inline(never) func inline3() {} // expected-note {{matches attribute here}} +@abi(func inline3()) +@inline(never) func inline3() {} -// @_transparent -- automatically cloned into @abi -@abi(@_transparent func transparent1()) +// @_transparent -- banned in @abi +@abi(@_transparent func transparent1()) // expected-error {{unused '_transparent' attribute in '@abi'}} {{6-19=}} @_transparent func transparent1() {} -@abi(@_transparent func transparent2()) // expected-error {{extra '_transparent' attribute in '@abi'}} {{6-19=}} +@abi(@_transparent func transparent2()) // expected-error {{unused '_transparent' attribute in '@abi'}} {{6-19=}} func transparent2() {} -@abi(func transparent3()) // expected-remark {{inferred '@_transparent' in '@abi' to match attribute on API}} -@_transparent func transparent3() {} // expected-note {{matches attribute here}} +@abi(func transparent3()) +@_transparent func transparent3() {} -// @_alwaysEmitIntoClient -- automatically cloned into @abi -@abi(@_alwaysEmitIntoClient func alwaysEmitIntoClient1()) +// @_alwaysEmitIntoClient -- banned in @abi +@abi(@_alwaysEmitIntoClient func alwaysEmitIntoClient1()) // expected-error {{unused '_alwaysEmitIntoClient' attribute in '@abi'}} {{6-28=}} @_alwaysEmitIntoClient func alwaysEmitIntoClient1() {} -@abi(@_alwaysEmitIntoClient func alwaysEmitIntoClient2()) // expected-error {{extra '_alwaysEmitIntoClient' attribute in '@abi'}} {{6-28=}} +@abi(@_alwaysEmitIntoClient func alwaysEmitIntoClient2()) // expected-error {{unused '_alwaysEmitIntoClient' attribute in '@abi'}} {{6-28=}} func alwaysEmitIntoClient2() {} -@abi(func alwaysEmitIntoClient3()) // expected-remark {{inferred '@_alwaysEmitIntoClient' in '@abi' to match attribute on API}} -@_alwaysEmitIntoClient func alwaysEmitIntoClient3() {} // expected-note {{matches attribute here}} +@abi(func alwaysEmitIntoClient3()) +@_alwaysEmitIntoClient func alwaysEmitIntoClient3() {} // @_optimize(none) -- banned in @abi @abi(@_optimize(none) func optimize1()) // expected-error {{unused '_optimize(none)' attribute in '@abi'}} {{6-22=}} @@ -1891,16 +1951,17 @@ class Required { required init(i3: Void) { fatalError() } // expected-note {{should match modifier here}} } -// lazy -- automatically cloned into @abi +// lazy -- banned both in and with @abi +// This introduces auxiliary decls whose ABI could not be controlled. class Lazy { - @abi(lazy var v1: Int) - lazy var v1: Int = 0 + @abi(lazy var v1: Int) // expected-error {{'lazy' is not compatible with '@abi' attribute}} {{8-12=}} + lazy var v1: Int = 0 // expected-error {{'lazy' is not compatible with '@abi' attribute}} {{3-8=}} - @abi(lazy var v2: Int) // expected-error {{extra 'lazy' modifier in '@abi'}} {{8-12=}} + @abi(lazy var v2: Int) // expected-error {{'lazy' is not compatible with '@abi' attribute}} {{8-12=}} var v2: Int = 0 - @abi(var v3: Int) // expected-remark {{inferred 'lazy' in '@abi' to match modifier on API}} - lazy var v3: Int = 0 // expected-note {{matches modifier here}} + @abi(var v3: Int) + lazy var v3: Int = 0 // expected-error {{'lazy' is not compatible with '@abi' attribute}} {{3-8=}} } // @_fixed_layout -- banned in @abi @@ -1975,15 +2036,15 @@ extension DynamicReplacement { // @_weakLinked -- tested in attr/attr_weaklinked.swift -// @_borrowed -- automatically cloned into @abi +// @_borrowed -- banned in @abi protocol BorrowedAttr { - @abi(@_borrowed var v1: Int) + @abi(@_borrowed var v1: Int) // expected-error {{unused '_borrowed' attribute in '@abi'}} {{8-18=}} @_borrowed var v1: Int { get set } - @abi(var v2: Int) // expected-remark {{inferred '@_borrowed' in '@abi' to match attribute on API}} - @_borrowed var v2: Int { get set } // expected-note {{matches attribute here}} + @abi(var v2: Int) + @_borrowed var v2: Int { get set } - @abi(@_borrowed var v3: Int) // expected-error {{extra '_borrowed' attribute in '@abi'}} {{8-18=}} + @abi(@_borrowed var v3: Int) // expected-error {{unused '_borrowed' attribute in '@abi'}} {{8-18=}} var v3: Int { get set } } diff --git a/test/attr/attr_abi_objc.swift b/test/attr/attr_abi_objc.swift index 3cb683e134a70..b16e0ae6c440a 100644 --- a/test/attr/attr_abi_objc.swift +++ b/test/attr/attr_abi_objc.swift @@ -1,6 +1,5 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature ABIAttribute -parse-as-library -Rabi-inference +// RUN: %target-typecheck-verify-swift -parse-as-library -// REQUIRES: swift_feature_ABIAttribute // REQUIRES: objc_interop import Foundation diff --git a/test/attr/attr_weaklinked.swift b/test/attr/attr_weaklinked.swift index a56dbf4bf8ecb..831afa281d32d 100644 --- a/test/attr/attr_weaklinked.swift +++ b/test/attr/attr_weaklinked.swift @@ -1,7 +1,6 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature ABIAttribute +// RUN: %target-typecheck-verify-swift // UNSUPPORTED: OS=windows-msvc -// REQUIRES: swift_feature_ABIAttribute @_weakLinked public func f() { } diff --git a/test/attr/feature_requirement.swift b/test/attr/feature_requirement.swift index f568a707b91ad..d8e6121311bfc 100644 --- a/test/attr/feature_requirement.swift +++ b/test/attr/feature_requirement.swift @@ -1,16 +1,16 @@ // RUN: %target-typecheck-verify-swift -parse-as-library -disable-experimental-parser-round-trip -verify-additional-prefix disabled- -// RUN: %target-typecheck-verify-swift -parse-as-library -verify-additional-prefix enabled- -enable-experimental-feature ABIAttribute +// RUN: %target-typecheck-verify-swift -parse-as-library -verify-additional-prefix enabled- -enable-experimental-feature CompileTimeValues // REQUIRES: asserts // This test checks whether DECL_ATTR_FEATURE_REQUIREMENT is being applied correctly. // It is expected to need occasional edits as experimental features are stabilized. -@abi(func fn()) -func fn() {} // expected-disabled-error@-1 {{'abi' attribute is only valid when experimental feature ABIAttribute is enabled}} +@const +public let x = 1 // expected-disabled-error@-1 {{'const' attribute is only valid when experimental feature CompileTimeValues is enabled}} -#if hasAttribute(abi) - #error("does have @abi") // expected-enabled-error {{does have @abi}} +#if hasAttribute(const) + #error("does have @const") // expected-enabled-error {{does have @const}} #else - #error("doesn't have @abi") // expected-disabled-error {{doesn't have @abi}} + #error("doesn't have @const") // expected-disabled-error {{doesn't have @const}} #endif