Skip to content

Finish implementing @abi (SE-0476) #81115

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,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
12 changes: 4 additions & 8 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -8468,14 +8468,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 %kindonly0 because "
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 @@ -257,6 +257,7 @@ LANGUAGE_FEATURE(SendableCompletionHandlers, 463, "Objective-C completion handle
LANGUAGE_FEATURE(AsyncExecutionBehaviorAttributes, 0, "@concurrent and nonisolated(nonsending)")
LANGUAGE_FEATURE(IsolatedConformances, 407, "Global-actor isolated conformances")
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 @@ -487,9 +488,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
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/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,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
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
55 changes: 12 additions & 43 deletions lib/Sema/TypeCheckAttrABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,60 +1102,29 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
};

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.
bool didDiagnose = false;
for (auto i : range(PBD->getNumPatternEntries())) {
SmallVector<VarDecl *, 8> VDs;
SmallVector<VarDecl *, 8> 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);
didDiagnose = 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);
didDiagnose = true;
}
}
}
if (didDiagnose)
return;

// Check the ABI PBD--this is what checks the underlying vars.
TypeChecker::typeCheckDecl(APBD);
}
Expand Down
4 changes: 0 additions & 4 deletions test/ASTGen/attrs.swift
Original file line number Diff line number Diff line change
@@ -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 \
Expand All @@ -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 \
Expand All @@ -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 \
Expand All @@ -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
Expand Down
17 changes: 17 additions & 0 deletions test/IDE/complete_decl_attribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -112,6 +117,7 @@ actor MyGenericGlobalActor<T> {
// 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: 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
Expand Down Expand Up @@ -169,6 +175,7 @@ actor MyGenericGlobalActor<T> {
// 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
Expand Down Expand Up @@ -197,6 +204,7 @@ actor MyGenericGlobalActor<T> {

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
Expand All @@ -207,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
Expand Down Expand Up @@ -234,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
Expand Down Expand Up @@ -293,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
Expand Down Expand Up @@ -347,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
Expand All @@ -365,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{{$}}
Expand Down
5 changes: 5 additions & 0 deletions test/IDE/complete_decl_attribute_feature_requirement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions test/IRGen/asmname.swift
Original file line number Diff line number Diff line change
@@ -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

Expand Down
23 changes: 23 additions & 0 deletions test/Macros/macro_expand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -719,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")
Expand Down
23 changes: 23 additions & 0 deletions test/Macros/macro_expand_peers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading