Skip to content

Commit 7fcce43

Browse files
committed
Tie attributes to language features
The new `DECL_ATTR_FEATURE_REQUIREMENT` macro in DeclAttr.def can be used to declare that an attribute should only be available when a related language feature is enabled. Effects: • `#if hasAttribute(someAttr)` will return `false` unless the required feature is enabled. • Code completion will not include the attribute unless the required feature is enabled. • `TypeChecker::checkDeclAttributes()` diagnoses non-implicit uses of the attribute. Add this mechanism and use it to tie @abi to the ABIAttribute feature. Also design tests for it.
1 parent 26df537 commit 7fcce43

File tree

9 files changed

+229
-11
lines changed

9 files changed

+229
-11
lines changed

include/swift/AST/Attr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/AST/StorageImpl.h"
3232
#include "swift/Basic/Debug.h"
3333
#include "swift/Basic/EnumTraits.h"
34+
#include "swift/Basic/Feature.h"
3435
#include "swift/Basic/InlineBitfield.h"
3536
#include "swift/Basic/Located.h"
3637
#include "swift/Basic/OptimizationMode.h"
@@ -475,6 +476,8 @@ class DeclAttribute : public AttributeBase {
475476
LLVM_READNONE
476477
static bool canAttributeAppearOnDeclKind(DeclAttrKind DAK, DeclKind DK);
477478

479+
static std::optional<Feature> getRequiredFeature(DeclAttrKind DK);
480+
478481
/// Returns the source name of the attribute, without the @ or any arguments.
479482
StringRef getAttrName() const;
480483

include/swift/AST/DeclAttr.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@
4242
DECL_ATTR_ALIAS(SPELLING, CLASS)
4343
#endif
4444

45+
// Diagnose any use of the attribute CLASS without FEATURE_NAME enabled,
46+
// and also enable other special behavior. If you use this for an experimental
47+
// feature, please add test cases to:
48+
//
49+
// * test/attr/feature_requirement.swift
50+
// * test/IDE/complete_decl_attribute_feature_requirement.swift
51+
#ifndef DECL_ATTR_FEATURE_REQUIREMENT
52+
#define DECL_ATTR_FEATURE_REQUIREMENT(CLASS, FEATURE_NAME)
53+
#endif
54+
4555
#ifndef LAST_DECL_ATTR
4656
#define LAST_DECL_ATTR(CLASS)
4757
#endif
@@ -516,6 +526,7 @@ DECL_ATTR(lifetime, Lifetime,
516526
DECL_ATTR(abi, ABI,
517527
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
518528
162)
529+
DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute)
519530

520531
LAST_DECL_ATTR(ABI)
521532

@@ -525,4 +536,5 @@ LAST_DECL_ATTR(ABI)
525536
#undef CONTEXTUAL_SIMPLE_DECL_ATTR
526537
#undef DECL_ATTR
527538
#undef CONTEXTUAL_DECL_ATTR
539+
#undef DECL_ATTR_FEATURE_REQUIREMENT
528540
#undef LAST_DECL_ATTR

include/swift/IDE/CompletionLookup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
597597
SourceLoc CodeCompletionLoc);
598598

599599
static bool canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil,
600-
bool IsConcurrencyEnabled,
600+
const LangOptions &langOpts,
601601
std::optional<DeclKind> DK, StringRef Name);
602602

603603
void getAttributeDeclCompletions(bool IsInSil, std::optional<DeclKind> DK);

lib/AST/Attr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,18 @@ uint64_t DeclAttribute::getOptions(DeclAttrKind DK) {
18881888
llvm_unreachable("bad DeclAttrKind");
18891889
}
18901890

1891+
std::optional<Feature> DeclAttribute::getRequiredFeature(DeclAttrKind DK) {
1892+
switch (DK) {
1893+
#define DECL_ATTR_FEATURE_REQUIREMENT(CLASS, FEATURE_NAME) \
1894+
case DeclAttrKind::CLASS: \
1895+
return Feature::FEATURE_NAME;
1896+
#include "swift/AST/DeclAttr.def"
1897+
default:
1898+
return std::nullopt;
1899+
}
1900+
llvm_unreachable("bad DeclAttrKind");
1901+
}
1902+
18911903
StringRef DeclAttribute::getAttrName() const {
18921904
switch (getKind()) {
18931905
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
@@ -3151,6 +3163,10 @@ static bool hasDeclAttribute(const LangOptions &langOpts,
31513163
if (DeclAttribute::isConcurrencyOnly(*kind))
31523164
return false;
31533165

3166+
if (auto feature = DeclAttribute::getRequiredFeature(*kind))
3167+
if (!langOpts.hasFeature(*feature))
3168+
return false;
3169+
31543170
return true;
31553171
}
31563172

lib/IDE/CodeCompletion.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ static void addKeyword(CodeCompletionResultSink &Sink, StringRef Name,
686686
}
687687

688688
static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
689-
bool IsConcurrencyEnabled) {
689+
const LangOptions &langOpts) {
690690
auto isTypeDeclIntroducer = [](CodeCompletionKeywordKind Kind,
691691
std::optional<DeclAttrKind> DAK) -> bool {
692692
switch (Kind) {
@@ -799,10 +799,16 @@ static void addDeclKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
799799
return;
800800

801801
// Remove keywords only available when concurrency is enabled.
802-
if (DAK.has_value() && !IsConcurrencyEnabled &&
802+
if (DAK.has_value() && !langOpts.EnableExperimentalConcurrency &&
803803
DeclAttribute::isConcurrencyOnly(*DAK))
804804
return;
805805

806+
// Remove experimental keywords.
807+
if (DAK.has_value())
808+
if (auto feature = DeclAttribute::getRequiredFeature(*DAK))
809+
if (!langOpts.hasFeature(*feature))
810+
return;
811+
806812
CodeCompletionFlair flair = getFlair(Kind, DAK);
807813

808814
// Special case for 'actor'. Get the same flair with 'kw_class'.
@@ -1018,8 +1024,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10181024
LLVM_FALLTHROUGH;
10191025
}
10201026
case CompletionKind::StmtOrExpr:
1021-
addDeclKeywords(Sink, CurDeclContext,
1022-
Context.LangOpts.EnableExperimentalConcurrency);
1027+
addDeclKeywords(Sink, CurDeclContext, Context.LangOpts);
10231028
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
10241029
addClosureSignatureKeywordsIfApplicable(Sink, CurDeclContext);
10251030

@@ -1120,8 +1125,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
11201125
.Default(false);
11211126
}) != ParsedKeywords.end();
11221127
if (!HasDeclIntroducer) {
1123-
addDeclKeywords(Sink, CurDeclContext,
1124-
Context.LangOpts.EnableExperimentalConcurrency);
1128+
addDeclKeywords(Sink, CurDeclContext, Context.LangOpts);
11251129
addLetVarKeywords(Sink);
11261130
}
11271131
break;

lib/IDE/CompletionLookup.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3008,7 +3008,7 @@ void CompletionLookup::getGenericRequirementCompletions(
30083008
}
30093009

30103010
bool CompletionLookup::canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil,
3011-
bool IsConcurrencyEnabled,
3011+
const LangOptions &langOpts,
30123012
std::optional<DeclKind> DK,
30133013
StringRef Name) {
30143014
if (DeclAttribute::isUserInaccessible(DAK))
@@ -3019,8 +3019,12 @@ bool CompletionLookup::canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil,
30193019
return false;
30203020
if (!IsInSil && DeclAttribute::isSilOnly(DAK))
30213021
return false;
3022-
if (!IsConcurrencyEnabled && DeclAttribute::isConcurrencyOnly(DAK))
3022+
if (!langOpts.EnableExperimentalConcurrency
3023+
&& DeclAttribute::isConcurrencyOnly(DAK))
30233024
return false;
3025+
if (auto feature = DeclAttribute::getRequiredFeature(DAK))
3026+
if (!langOpts.hasFeature(*feature))
3027+
return false;
30243028
if (!DK.has_value())
30253029
return true;
30263030
// Hide underscored attributes even if they are not marked as user
@@ -3044,11 +3048,10 @@ void CompletionLookup::getAttributeDeclCompletions(bool IsInSil,
30443048
#include "swift/AST/DeclNodes.def"
30453049
}
30463050
}
3047-
bool IsConcurrencyEnabled = Ctx.LangOpts.EnableExperimentalConcurrency;
30483051
std::string Description = TargetName.str() + " Attribute";
30493052
#define DECL_ATTR_ALIAS(KEYWORD, NAME) DECL_ATTR(KEYWORD, NAME, 0, 0)
30503053
#define DECL_ATTR(KEYWORD, NAME, ...) \
3051-
if (canUseAttributeOnDecl(DeclAttrKind::NAME, IsInSil, IsConcurrencyEnabled, \
3054+
if (canUseAttributeOnDecl(DeclAttrKind::NAME, IsInSil, Ctx.LangOpts, \
30523055
DK, #KEYWORD)) \
30533056
addDeclAttrKeyword(#KEYWORD, Description);
30543057
#include "swift/AST/DeclAttr.def"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,18 @@ void TypeChecker::checkDeclAttributes(Decl *D) {
17881788
for (auto attr : D->getExpandedAttrs()) {
17891789
if (!attr->isValid()) continue;
17901790

1791+
// If the attribute requires a feature that is not enabled, and it is not
1792+
// an implicit attribute, diagnose and disable it.
1793+
if (auto feature = DeclAttribute::getRequiredFeature(attr->getKind())) {
1794+
if (!attr->isImplicit()
1795+
&& !D->getASTContext().LangOpts.hasFeature(*feature)) {
1796+
Checker.diagnoseAndRemoveAttr(attr, diag::requires_experimental_feature,
1797+
attr->getAttrName(), false,
1798+
getFeatureName(*feature));
1799+
continue;
1800+
}
1801+
}
1802+
17911803
// If Attr.def says that the attribute cannot appear on this kind of
17921804
// declaration, diagnose it and disable it.
17931805
if (attr->canAppearOnDecl(D)) {
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD2 | %FileCheck %s -check-prefixes=KEYWORD2,KEYWORD2_DISABLED
2+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD3 | %FileCheck %s -check-prefixes=KEYWORD3,KEYWORD3_DISABLED
3+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD3_2 | %FileCheck %s -check-prefixes=KEYWORD3,KEYWORD3_DISABLED
4+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD4 | %FileCheck %s -check-prefixes=KEYWORD4,KEYWORD4_DISABLED
5+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD5 | %FileCheck %s -check-prefixes=KEYWORD5,KEYWORD5_DISABLED
6+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_GLOBALVAR | %FileCheck %s -check-prefixes=ON_GLOBALVAR,ON_GLOBALVAR_DISABLED
7+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_INIT | %FileCheck %s -check-prefixes=ON_INIT,ON_INIT_DISABLED
8+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_PROPERTY | %FileCheck %s -check-prefixes=ON_PROPERTY,ON_PROPERTY_DISABLED
9+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_METHOD | %FileCheck %s -check-prefixes=ON_METHOD,ON_METHOD_DISABLED
10+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_PARAM_1 | %FileCheck %s -check-prefixes=ON_PARAM,ON_PARAM_DISABLED
11+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_PARAM_2 | %FileCheck %s -check-prefixes=ON_PARAM,ON_PARAM_DISABLED
12+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_MEMBER_INDEPENDENT_1 | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_DISABLED
13+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_MEMBER_INDEPENDENT_2 | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_DISABLED
14+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ON_MEMBER_LAST | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_DISABLED
15+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_CLOSURE | %FileCheck %s -check-prefixes=IN_CLOSURE,IN_CLOSURE_DISABLED
16+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD_INDEPENDENT_1 | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_DISABLED
17+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD_INDEPENDENT_2 | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_DISABLED
18+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=KEYWORD_LAST | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_DISABLED
19+
20+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD2 | %FileCheck %s -check-prefixes=KEYWORD2,KEYWORD2_ENABLED
21+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD3 | %FileCheck %s -check-prefixes=KEYWORD3,KEYWORD3_ENABLED
22+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD3_2 | %FileCheck %s -check-prefixes=KEYWORD3,KEYWORD3_ENABLED
23+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD4 | %FileCheck %s -check-prefixes=KEYWORD4,KEYWORD4_ENABLED
24+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD5 | %FileCheck %s -check-prefixes=KEYWORD5,KEYWORD5_ENABLED
25+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_GLOBALVAR | %FileCheck %s -check-prefixes=ON_GLOBALVAR,ON_GLOBALVAR_ENABLED
26+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_INIT | %FileCheck %s -check-prefixes=ON_INIT,ON_INIT_ENABLED
27+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_PROPERTY | %FileCheck %s -check-prefixes=ON_PROPERTY,ON_PROPERTY_ENABLED
28+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_METHOD | %FileCheck %s -check-prefixes=ON_METHOD,ON_METHOD_ENABLED
29+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_PARAM_1 | %FileCheck %s -check-prefixes=ON_PARAM,ON_PARAM_ENABLED
30+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_PARAM_2 | %FileCheck %s -check-prefixes=ON_PARAM,ON_PARAM_ENABLED
31+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_MEMBER_INDEPENDENT_1 | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_ENABLED
32+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_MEMBER_INDEPENDENT_2 | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_ENABLED
33+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=ON_MEMBER_LAST | %FileCheck %s -check-prefixes=ON_MEMBER_LAST,ON_MEMBER_LAST_ENABLED
34+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=IN_CLOSURE | %FileCheck %s -check-prefixes=IN_CLOSURE,IN_CLOSURE_ENABLED
35+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD_INDEPENDENT_1 | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_ENABLED
36+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD_INDEPENDENT_2 | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_ENABLED
37+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -enable-experimental-feature ABIAttribute -code-completion-token=KEYWORD_LAST | %FileCheck %s -check-prefixes=KEYWORD_LAST,KEYWORD_LAST_ENABLED
38+
39+
// NOTE: Please do not include the ", N items" after "Begin completions". The
40+
// item count creates needless merge conflicts given that an "End completions"
41+
// line exists for each test.
42+
43+
@#^KEYWORD2^# func method(){}
44+
45+
// KEYWORD2: Begin completions
46+
// KEYWORD2_ENABLED-DAG: Keyword/None: abi[#Func Attribute#]; name=abi
47+
// KEYWORD2_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
48+
// KEYWORD2: End completions
49+
50+
@#^KEYWORD3^# class C {}
51+
52+
// KEYWORD3: Begin completions
53+
// KEYWORD3_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
54+
// KEYWORD3_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
55+
// KEYWORD3: End completions
56+
57+
@#^KEYWORD3_2^#IB class C2 {}
58+
// Same as KEYWORD3.
59+
60+
@#^KEYWORD4^# enum E {}
61+
// KEYWORD4: Begin completions
62+
// KEYWORD4_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
63+
// KEYWORD4_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
64+
// KEYWORD4: End completions
65+
66+
@#^KEYWORD5^# struct S{}
67+
// KEYWORD5: Begin completions
68+
// KEYWORD5_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
69+
// KEYWORD5_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
70+
// KEYWORD5: End completions
71+
72+
@#^ON_GLOBALVAR^# var globalVar
73+
// ON_GLOBALVAR: Begin completions
74+
// ON_GLOBALVAR_ENABLED-DAG: Keyword/None: abi[#Var Attribute#]; name=abi
75+
// ON_GLOBALVAR_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
76+
// ON_GLOBALVAR: End completions
77+
78+
struct _S {
79+
@#^ON_INIT^# init()
80+
// ON_INIT: Begin completions
81+
// ON_INIT_ENABLED-DAG: Keyword/None: abi[#Constructor Attribute#]; name=abi
82+
// ON_INIT_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
83+
// ON_INIT: End completions
84+
85+
@#^ON_PROPERTY^# var foo
86+
// ON_PROPERTY: Begin completions
87+
// ON_PROPERTY_ENABLED-DAG: Keyword/None: abi[#Var Attribute#]; name=abi
88+
// ON_PROPERTY_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
89+
// ON_PROPERTY: End completions
90+
91+
@#^ON_METHOD^# private
92+
func foo()
93+
// ON_METHOD: Begin completions
94+
// ON_METHOD_ENABLED-DAG: Keyword/None: abi[#Func Attribute#]; name=abi
95+
// ON_METHOD_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
96+
// ON_METHOD: End completions
97+
98+
99+
func bar(@#^ON_PARAM_1^#)
100+
// ON_PARAM: Begin completions
101+
// ON_PARAM_ENABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
102+
// ON_PARAM_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
103+
// ON_PARAM: End completions
104+
105+
func bar(
106+
@#^ON_PARAM_2^#
107+
108+
arg: Int
109+
)
110+
// Same as ON_PARAM.
111+
112+
@#^ON_MEMBER_INDEPENDENT_1^#
113+
114+
func dummy1() {}
115+
// Same as ON_MEMBER_LAST.
116+
117+
@#^ON_MEMBER_INDEPENDENT_2^#
118+
func dummy2() {}
119+
// Same as ON_MEMBER_LAST.
120+
121+
122+
@#^ON_MEMBER_LAST^#
123+
// ON_MEMBER_LAST: Begin completions
124+
// ON_MEMBER_LAST_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi
125+
// ON_MEMBER_LAST_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
126+
// ON_MEMBER_LAST: End completions
127+
}
128+
129+
func takeClosure(_: () -> Void) {
130+
takeClosure { @#^IN_CLOSURE^# in
131+
print("x")
132+
}
133+
}
134+
// IN_CLOSURE: Begin completions
135+
// FIXME: Not valid in this position (but CompletionLookup can't tell that)
136+
// IN_CLOSURE_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi
137+
// IN_CLOSURE_DISABLED-NOT: Keyword/None: abi[#{{.*}} Attribute#]; name=abi
138+
// IN_CLOSURE: End completions
139+
140+
@#^KEYWORD_INDEPENDENT_1^#
141+
142+
func dummy1() {}
143+
// Same as KEYWORD_LAST.
144+
145+
@#^KEYWORD_INDEPENDENT_2^#
146+
func dummy2() {}
147+
// Same as KEYWORD_LAST.
148+
149+
@#^KEYWORD_LAST^#
150+
151+
// KEYWORD_LAST: Begin completions
152+
// KEYWORD_LAST_ENABLED-DAG: Keyword/None: abi[#Declaration Attribute#]; name=abi
153+
// KEYWORD_LAST_DISABLED-NOT: Keyword/None: abi[#Declaration Attribute#]; name=abi
154+
// KEYWORD_LAST: End completions

test/attr/feature_requirement.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-typecheck-verify-swift -parse-as-library -verify-additional-prefix disabled-
2+
// RUN: %target-typecheck-verify-swift -parse-as-library -verify-additional-prefix enabled- -enable-experimental-feature ABIAttribute
3+
4+
// This test checks whether DECL_ATTR_FEATURE_REQUIREMENT is being applied correctly.
5+
// It is expected to need occasional edits as experimental features are stabilized.
6+
7+
@abi(func fn())
8+
func fn() {} // expected-disabled-error@-1 {{'abi' attribute is only valid when experimental feature ABIAttribute is enabled}}
9+
10+
#if hasAttribute(abi)
11+
#error("does have @abi") // expected-enabled-error {{does have @abi}}
12+
#else
13+
#error("doesn't have @abi") // expected-disabled-error {{doesn't have @abi}}
14+
#endif

0 commit comments

Comments
 (0)