Skip to content

Commit ee9c066

Browse files
committed
Introduce a new Initializer subclass for the arguments of custom attributes
Since the introduction of custom attributes (as part of property wrappers), we've modeled the context of expressions within these attributes as PatternBindingInitializers. These PatternBindingInitializers would get wired in to the variable declarations they apply to, establishing the appropriate declaration context hierarchy. This worked because property wrappers only every applied to---you guessed it!---properties, so the PatternBindingInitializer would always get filled in. When custom attributes were extended to apply to anything for the purposes of macros, the use of PatternBindingInitializer became less appropriate. Specifically, the binding declaration would never get filled in (it's always NULL), so any place in the compiler that accesses the binding might have to deal with it being NULL, which is a new requirement. Few did, crashes ensued. Rather than continue to play whack-a-mole with the abused PatternBindingInitializer, introduce a new CustomAttributeInitializer to model the context of custom attribute arguments. When the attributes are assigned to a declaration that has a PatternBindingInitializer, we reparent this new initializer to the PatternBindingInitializer. This helps separate out the logic for custom attributes vs. actual initializers. Fixes #76409 / rdar://136997841
1 parent 95c3011 commit ee9c066

21 files changed

+160
-74
lines changed

include/swift/AST/ASTBridging.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,14 @@ SWIFT_NAME("getter:BridgedPatternBindingInitializer.asDeclContext(self:)")
536536
BridgedDeclContext BridgedPatternBindingInitializer_asDeclContext(
537537
BridgedPatternBindingInitializer cInit);
538538

539+
SWIFT_NAME("BridgedCustomAttributeInitializer.create(declContext:)")
540+
BridgedCustomAttributeInitializer
541+
BridgedCustomAttributeInitializer_create(BridgedDeclContext cDeclContext);
542+
543+
SWIFT_NAME("getter:BridgedCustomAttributeInitializer.asDeclContext(self:)")
544+
BridgedDeclContext BridgedCustomAttributeInitializer_asDeclContext(
545+
BridgedCustomAttributeInitializer cInit);
546+
539547
SWIFT_NAME("getter:BridgedClosureExpr.asDeclContext(self:)")
540548
BridgedDeclContext
541549
BridgedClosureExpr_asDeclContext(BridgedClosureExpr cClosure);
@@ -613,7 +621,7 @@ SWIFT_NAME(
613621
"BridgedCustomAttr.createParsed(_:atLoc:type:initContext:argumentList:)")
614622
BridgedCustomAttr BridgedCustomAttr_createParsed(
615623
BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedTypeRepr cType,
616-
BridgedNullablePatternBindingInitializer cInitContext,
624+
BridgedNullableCustomAttributeInitializer cInitContext,
617625
BridgedNullableArgumentList cArgumentList);
618626

619627
SWIFT_NAME("BridgedDocumentationAttr.createParsed(_:atLoc:range:metadata:"

include/swift/AST/ASTBridgingWrappers.def

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ AST_BRIDGING_WRAPPER_NULLABLE(GenericParamList)
8383
AST_BRIDGING_WRAPPER_NULLABLE(TrailingWhereClause)
8484
AST_BRIDGING_WRAPPER_NULLABLE(ParameterList)
8585
AST_BRIDGING_WRAPPER_NULLABLE(PatternBindingInitializer)
86+
AST_BRIDGING_WRAPPER_NULLABLE(CustomAttributeInitializer)
8687
AST_BRIDGING_WRAPPER_NONNULL(TypeAttributes)
8788
AST_BRIDGING_WRAPPER_NONNULL(CustomAttribute)
8889
AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList)

include/swift/AST/Attr.h

+9-4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class AbstractFunctionDecl;
6060
class FuncDecl;
6161
class ClassDecl;
6262
class AccessorDecl;
63+
class CustomAttributeInitializer;
6364
class GenericFunctionType;
6465
class LazyConformanceLoader;
6566
class LazyMemberLoader;
@@ -1861,13 +1862,13 @@ class ClangImporterSynthesizedTypeAttr : public DeclAttribute {
18611862
class CustomAttr final : public DeclAttribute {
18621863
TypeExpr *typeExpr;
18631864
ArgumentList *argList;
1864-
PatternBindingInitializer *initContext;
1865+
CustomAttributeInitializer *initContext;
18651866
Expr *semanticInit = nullptr;
18661867

18671868
mutable unsigned isArgUnsafeBit : 1;
18681869

18691870
CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
1870-
PatternBindingInitializer *initContext, ArgumentList *argList,
1871+
CustomAttributeInitializer *initContext, ArgumentList *argList,
18711872
bool implicit);
18721873

18731874
public:
@@ -1878,7 +1879,7 @@ class CustomAttr final : public DeclAttribute {
18781879
}
18791880

18801881
static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
1881-
PatternBindingInitializer *initContext,
1882+
CustomAttributeInitializer *initContext,
18821883
ArgumentList *argList, bool implicit = false);
18831884

18841885
TypeExpr *getTypeExpr() const { return typeExpr; }
@@ -1911,7 +1912,7 @@ class CustomAttr final : public DeclAttribute {
19111912
Expr *getSemanticInit() const { return semanticInit; }
19121913
void setSemanticInit(Expr *expr) { semanticInit = expr; }
19131914

1914-
PatternBindingInitializer *getInitContext() const { return initContext; }
1915+
CustomAttributeInitializer *getInitContext() const { return initContext; }
19151916

19161917
static bool classof(const DeclAttribute *DA) {
19171918
return DA->getKind() == DeclAttrKind::Custom;
@@ -3041,6 +3042,10 @@ class DeclAttributes {
30413042
const_cast<const DeclAttributes *>(this)->getEffectiveSendableAttr());
30423043
}
30433044

3045+
/// Try to find the custom attribute initializer within the list of
3046+
/// attributes.
3047+
CustomAttributeInitializer *findCustomAttributeInitializer() const;
3048+
30443049
public:
30453050
template <typename ATTR, bool AllowInvalid>
30463051
using AttributeKindRange =

include/swift/AST/Initializer.h

+35
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
#include "swift/AST/DeclContext.h"
2424

25+
namespace llvm {
26+
class raw_ostream;
27+
}
28+
2529
namespace swift {
2630
class ParamDecl;
2731
class PatternBindingDecl;
@@ -36,6 +40,9 @@ enum class InitializerKind : uint8_t {
3640

3741
/// A property wrapper initialization expression.
3842
PropertyWrapper,
43+
44+
/// An expression within a custom attribute.
45+
CustomAttribute,
3946
};
4047

4148
/// An Initializer is a kind of DeclContext used for expressions that
@@ -176,6 +183,34 @@ class PropertyWrapperInitializer : public Initializer {
176183
}
177184
};
178185

186+
/// An expression within a custom attribute. The parent context is the
187+
/// context in which the attributed declaration occurs.
188+
class CustomAttributeInitializer : public Initializer {
189+
public:
190+
explicit CustomAttributeInitializer(DeclContext *parent)
191+
: Initializer(InitializerKind::CustomAttribute, parent) {}
192+
193+
static CustomAttributeInitializer *create(DeclContext *parent) {
194+
return new (parent->getASTContext()) CustomAttributeInitializer(parent);
195+
}
196+
197+
void setEnclosingInitializer(Initializer *newParent) {
198+
setParent(newParent);
199+
}
200+
201+
static bool classof(const DeclContext *DC) {
202+
if (auto init = dyn_cast<Initializer>(DC))
203+
return classof(init);
204+
return false;
205+
}
206+
207+
static bool classof(const Initializer *I) {
208+
return I->getInitializerKind() == InitializerKind::CustomAttribute;
209+
}
210+
};
211+
212+
void simple_display(llvm::raw_ostream &out, Initializer *init);
213+
179214
} // end namespace swift
180215

181216
#endif

include/swift/Parse/Parser.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ class Parser {
999999
/// Parse an #if ... #endif containing only attributes.
10001000
ParserStatus parseIfConfigAttributes(
10011001
DeclAttributes &attributes, bool ifConfigsAreDeclAttrs,
1002-
PatternBindingInitializer *initContext);
1002+
CustomAttributeInitializer *&initContext);
10031003

10041004
/// Parse a #error or #warning diagnostic.
10051005
ParserResult<PoundDiagnosticDecl> parseDeclPoundDiagnostic();
@@ -1027,7 +1027,7 @@ class Parser {
10271027
/// This is the inner loop, which can be called recursively.
10281028
ParserStatus parseDeclAttributeList(DeclAttributes &Attributes,
10291029
bool IfConfigsAreDeclAttrs,
1030-
PatternBindingInitializer *initContext);
1030+
CustomAttributeInitializer *&initContext);
10311031

10321032
/// Parse the optional attributes before a closure declaration.
10331033
ParserStatus parseClosureDeclAttributeList(DeclAttributes &Attributes);
@@ -1162,7 +1162,7 @@ class Parser {
11621162
/// Parse a specific attribute.
11631163
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
11641164
SourceLoc AtEndLoc,
1165-
PatternBindingInitializer *&initContext,
1165+
CustomAttributeInitializer *&initContext,
11661166
bool isFromClangAttribute = false);
11671167

11681168
bool isCustomAttributeArgument();
@@ -1177,7 +1177,7 @@ class Parser {
11771177
/// will get filled in by this function. The same variable should be provided
11781178
/// for every custom attribute within the same attribute list.
11791179
ParserResult<CustomAttr> parseCustomAttribute(
1180-
SourceLoc atLoc, PatternBindingInitializer *&initContext);
1180+
SourceLoc atLoc, CustomAttributeInitializer *&initContext);
11811181

11821182
ParserStatus parseNewDeclAttribute(DeclAttributes &Attributes,
11831183
SourceLoc AtLoc, DeclAttrKind DK,
@@ -1479,7 +1479,7 @@ class Parser {
14791479

14801480
ParserStatus parseTypeAttribute(TypeOrCustomAttr &result, SourceLoc AtLoc,
14811481
SourceLoc AtEndLoc, ParseTypeReason reason,
1482-
PatternBindingInitializer *&initContext,
1482+
CustomAttributeInitializer *&initContext,
14831483
bool justChecking = false);
14841484

14851485
ParserResult<TypeRepr> parseOldStyleProtocolComposition();

lib/AST/ASTDumper.cpp

+1-11
Original file line numberDiff line numberDiff line change
@@ -1911,17 +1911,7 @@ void swift::printContext(raw_ostream &os, DeclContext *dc) {
19111911
break;
19121912

19131913
case DeclContextKind::Initializer:
1914-
switch (cast<Initializer>(dc)->getInitializerKind()) {
1915-
case InitializerKind::PatternBinding:
1916-
os << "pattern binding initializer";
1917-
break;
1918-
case InitializerKind::DefaultArgument:
1919-
os << "default argument initializer";
1920-
break;
1921-
case InitializerKind::PropertyWrapper:
1922-
os << "property wrapper initializer";
1923-
break;
1924-
}
1914+
simple_display(os, cast<Initializer>(dc));
19251915
break;
19261916

19271917
case DeclContextKind::TopLevelCodeDecl:

lib/AST/ASTMangler.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -2541,6 +2541,12 @@ void ASTMangler::appendContext(const DeclContext *ctx,
25412541
}
25422542
return;
25432543
}
2544+
2545+
case InitializerKind::CustomAttribute: {
2546+
BaseEntitySignature nullBase(nullptr);
2547+
appendContext(ctx->getParent(), nullBase, useModuleName);
2548+
return;
2549+
}
25442550
}
25452551
llvm_unreachable("bad initializer kind");
25462552
}

lib/AST/Attr.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -2632,7 +2632,7 @@ ProtocolDecl *ImplementsAttr::getProtocol(DeclContext *dc) const {
26322632
}
26332633

26342634
CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
2635-
PatternBindingInitializer *initContext,
2635+
CustomAttributeInitializer *initContext,
26362636
ArgumentList *argList, bool implicit)
26372637
: DeclAttribute(DeclAttrKind::Custom, atLoc, range, implicit),
26382638
typeExpr(type), argList(argList), initContext(initContext) {
@@ -2641,7 +2641,7 @@ CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
26412641
}
26422642

26432643
CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
2644-
PatternBindingInitializer *initContext,
2644+
CustomAttributeInitializer *initContext,
26452645
ArgumentList *argList, bool implicit) {
26462646
assert(type);
26472647
SourceRange range(atLoc, type->getSourceRange().End);
@@ -2881,3 +2881,13 @@ bool swift::hasAttribute(const LangOptions &langOpts,
28812881

28822882
return false;
28832883
}
2884+
2885+
CustomAttributeInitializer *
2886+
DeclAttributes::findCustomAttributeInitializer() const {
2887+
for (auto custom : getAttributes<CustomAttr>()) {
2888+
if (auto initContext = custom->getInitContext())
2889+
return initContext;
2890+
}
2891+
2892+
return nullptr;
2893+
}

lib/AST/Bridging/DeclAttributeBridging.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
134134

135135
BridgedCustomAttr BridgedCustomAttr_createParsed(
136136
BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedTypeRepr cType,
137-
BridgedNullablePatternBindingInitializer cInitContext,
137+
BridgedNullableCustomAttributeInitializer cInitContext,
138138
BridgedNullableArgumentList cArgumentList) {
139139
ASTContext &context = cContext.unbridged();
140140
return CustomAttr::create(

lib/AST/Bridging/DeclContextBridging.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ BridgedDeclContext BridgedPatternBindingInitializer_asDeclContext(
3131
return cInit.unbridged();
3232
}
3333

34+
BridgedCustomAttributeInitializer
35+
BridgedCustomAttributeInitializer_create(BridgedDeclContext cDeclContext) {
36+
return CustomAttributeInitializer::create(cDeclContext.unbridged());
37+
}
38+
39+
BridgedDeclContext BridgedCustomAttributeInitializer_asDeclContext(
40+
BridgedCustomAttributeInitializer cInit) {
41+
return cInit.unbridged();
42+
}
43+
3444
BridgedDeclContext
3545
BridgedClosureExpr_asDeclContext(BridgedClosureExpr cClosure) {
3646
return cClosure.unbridged();

lib/AST/Decl.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -2061,9 +2061,18 @@ PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
20612061
// FIXME: We ought to reconsider this since it won't recontextualize any
20622062
// closures/decls present in the initialization expr. This currently should
20632063
// only affect implicit code though.
2064-
if (!initContext && !Parent->isLocalContext())
2064+
if (!initContext && !Parent->isLocalContext()) {
20652065
initContext = PatternBindingInitializer::create(Parent);
20662066

2067+
}
2068+
2069+
if (auto firstVar = PBD->getAnchoringVarDecl(idx)) {
2070+
if (auto attributeInit =
2071+
firstVar->getAttrs().findCustomAttributeInitializer()) {
2072+
attributeInit->setEnclosingInitializer(initContext);
2073+
}
2074+
}
2075+
20672076
// We need to call setPattern to ensure the VarDecls in the pattern have
20682077
// the PatternBindingDecl set as their parent. We also need to call
20692078
// setInitContext to setup the context.

lib/AST/DeclContext.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,9 @@ unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent,
869869
}
870870
break;
871871
}
872+
case InitializerKind::CustomAttribute:
873+
OS << " CustomAttribute";
874+
break;
872875
}
873876
break;
874877
}

lib/AST/TypeCheckRequests.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,9 @@ void swift::simple_display(llvm::raw_ostream &out, Initializer *init) {
14701470
case InitializerKind::PropertyWrapper:
14711471
out << "property wrapper initializer";
14721472
break;
1473+
case InitializerKind::CustomAttribute:
1474+
out << "custom attribute initializer";
1475+
break;
14731476
}
14741477
}
14751478

lib/ASTGen/Sources/ASTGen/Bridge.swift

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extension BridgedNullableGenericParamList: /*@retroactive*/ swiftASTGen.BridgedN
3434
extension BridgedNullableTrailingWhereClause: /*@retroactive*/ swiftASTGen.BridgedNullable {}
3535
extension BridgedNullableParameterList: /*@retroactive*/ swiftASTGen.BridgedNullable {}
3636
extension BridgedNullablePatternBindingInitializer: /*@retroactive*/ swiftASTGen.BridgedNullable {}
37+
extension BridgedNullableCustomAttributeInitializer: /*@retroactive*/ swiftASTGen.BridgedNullable {}
3738
extension BridgedNullableArgumentList: /*@retroactive*/ swiftASTGen.BridgedNullable {}
3839

3940
extension BridgedIdentifier: /*@retroactive*/ Swift.Equatable {
@@ -80,6 +81,9 @@ extension BridgedParameterList: BridgedHasNullable {
8081
extension BridgedPatternBindingInitializer: BridgedHasNullable {
8182
typealias Nullable = BridgedNullablePatternBindingInitializer
8283
}
84+
extension BridgedCustomAttributeInitializer: BridgedHasNullable {
85+
typealias Nullable = BridgedNullableCustomAttributeInitializer
86+
}
8387
extension BridgedArgumentList: BridgedHasNullable {
8488
typealias Nullable = BridgedNullableArgumentList
8589
}

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension ASTGenVisitor {
2222
var attributes: BridgedDeclAttributes
2323
var staticSpelling: BridgedStaticSpelling
2424
var staticLoc: BridgedSourceLoc
25-
var initContext: BridgedPatternBindingInitializer?
25+
var initContext: BridgedCustomAttributeInitializer?
2626
}
2727

2828
func generateDeclAttributes(_ node: some WithAttributesSyntax & WithModifiersSyntax, allowStatic: Bool) -> DeclAttributesResult {
@@ -56,7 +56,7 @@ extension ASTGenVisitor {
5656

5757
// '@' attributes.
5858
// FIXME: Factor out this and share it with 'generate(accessorDecl:)'.
59-
var initContext: BridgedPatternBindingInitializer? = nil
59+
var initContext: BridgedCustomAttributeInitializer? = nil
6060
visitIfConfigElements(node.attributes, of: AttributeSyntax.self) { element in
6161
switch element {
6262
case .ifConfigDecl(let ifConfigDecl):
@@ -100,7 +100,7 @@ extension ASTGenVisitor {
100100

101101
// MARK: - Decl attributes
102102
extension ASTGenVisitor {
103-
func generateDeclAttribute(attribute node: AttributeSyntax, initContext: inout BridgedPatternBindingInitializer?) -> BridgedDeclAttribute? {
103+
func generateDeclAttribute(attribute node: AttributeSyntax, initContext: inout BridgedCustomAttributeInitializer?) -> BridgedDeclAttribute? {
104104
if let identTy = node.attributeName.as(IdentifierTypeSyntax.self) {
105105
let attrName = identTy.name.rawText
106106
let attrKind = BridgedDeclAttrKind(from: attrName.bridged)
@@ -1513,7 +1513,7 @@ extension ASTGenVisitor {
15131513
)
15141514
}
15151515

1516-
func generateCustomAttr(attribute node: AttributeSyntax, initContext: inout BridgedPatternBindingInitializer?) -> BridgedCustomAttr? {
1516+
func generateCustomAttr(attribute node: AttributeSyntax, initContext: inout BridgedCustomAttributeInitializer?) -> BridgedCustomAttr? {
15171517
let type = self.generate(type: node.attributeName)
15181518

15191519
let argList: BridgedArgumentList?
@@ -1524,7 +1524,7 @@ extension ASTGenVisitor {
15241524
}
15251525

15261526
if !self.declContext.isLocalContext && initContext == nil {
1527-
initContext = BridgedPatternBindingInitializer.create(declContext: self.declContext)
1527+
initContext = BridgedCustomAttributeInitializer.create(declContext: self.declContext)
15281528
}
15291529
argList = withDeclContext(initContext?.asDeclContext ?? self.declContext) {
15301530
self.generateArgumentList(

lib/ASTGen/Sources/ASTGen/Decls.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ extension ASTGenVisitor {
487487
// ensures that property initializers are correctly treated as being in a
488488
// local context).
489489
if !self.declContext.isLocalContext {
490-
initContext = attrs.initContext ?? .create(declContext: self.declContext)
490+
initContext = .create(declContext: self.declContext)
491491
}
492492
initExpr = withDeclContext(initContext?.asDeclContext ?? self.declContext) {
493493
generate(expr: initializer.value)

lib/ASTGen/Sources/ASTGen/Exprs.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ extension ASTGenVisitor {
232232
return .underlying(attribute)
233233
}
234234
} body: { node in
235-
var initCtx: BridgedPatternBindingInitializer?
235+
var initCtx: BridgedCustomAttributeInitializer?
236236
if let attr = self.generateDeclAttribute(attribute: node, initContext: &initCtx) {
237237
result.attributes.add(attr)
238238
}

0 commit comments

Comments
 (0)