Skip to content

Commit 3c47c4f

Browse files
authored
Merge pull request #63371 from DougGregor/semantic-attr-primary-walk
2 parents eda5657 + 69edc78 commit 3c47c4f

File tree

5 files changed

+113
-14
lines changed

5 files changed

+113
-14
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ void TypeChecker::checkDeclAttributes(Decl *D) {
14981498
llvm::SmallVector<AvailableAttr *, 4> availableAttrs;
14991499
llvm::SmallVector<BackDeployAttr *, 4> backDeployAttrs;
15001500
llvm::SmallVector<OriginallyDefinedInAttr*, 4> ODIAttrs;
1501-
for (auto attr : D->getAttrs()) {
1501+
for (auto attr : D->getSemanticAttrs()) {
15021502
if (!attr->isValid()) continue;
15031503

15041504
// If Attr.def says that the attribute cannot appear on this kind of

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,12 +1993,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19931993
checkAccessControl(PGD);
19941994
}
19951995

1996-
void visitMissingDecl(MissingDecl *missing) {
1997-
// FIXME: Expanded attribute lists should be type checked against
1998-
// the real declaration they will be attached to. Attempting to
1999-
// type check a missing decl should produce an error.
2000-
TypeChecker::checkDeclAttributes(missing);
2001-
}
1996+
void visitMissingDecl(MissingDecl *missing) { }
20021997

20031998
void visitMissingMemberDecl(MissingMemberDecl *MMD) {
20041999
llvm_unreachable("should always be type-checked already");

lib/Sema/TypeCheckMacros.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ bool ExpandMemberAttributeMacros::evaluate(Evaluator &evaluator,
334334
if (!parentDecl)
335335
return false;
336336

337+
if (isa<PatternBindingDecl>(decl))
338+
return false;
339+
337340
bool addedAttributes = false;
338341
parentDecl->forEachAttachedMacro(MacroRole::MemberAttribute,
339342
[&](CustomAttr *attr, MacroDecl *macro) {
@@ -973,13 +976,6 @@ bool swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) {
973976
auto *dc = member->getInnermostDeclContext();
974977
auto topLevelDecls = macroSourceFile->getTopLevelDecls();
975978
for (auto decl : topLevelDecls) {
976-
// FIXME: We want to type check decl attributes applied to
977-
// the real declaration, ideally by appending the new attributes
978-
// to the result and changing TypeChecker::checkDeclAttributes
979-
// to use the semantic attribute list.
980-
decl->setDeclContext(dc);
981-
TypeChecker::typeCheckDecl(decl);
982-
983979
// Add the new attributes to the semantic attribute list.
984980
SmallVector<DeclAttribute *, 2> attrs(decl->getAttrs().begin(),
985981
decl->getAttrs().end());

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,97 @@ public struct AddMembers: MemberMacro {
439439
]
440440
}
441441
}
442+
443+
/// Implementation of the `wrapStoredProperties` macro, which can be
444+
/// used to apply an attribute to all of the stored properties of a type.
445+
///
446+
/// This macro demonstrates member-attribute macros.
447+
public struct WrapStoredPropertiesMacro: MemberAttributeMacro {
448+
public static func expansion<
449+
Declaration: DeclGroupSyntax,
450+
Context: MacroExpansionContext
451+
>(
452+
of node: AttributeSyntax,
453+
attachedTo decl: Declaration,
454+
providingAttributesFor member: DeclSyntax,
455+
in context: Context
456+
) throws -> [AttributeSyntax] {
457+
guard let property = member.as(VariableDeclSyntax.self),
458+
property.isStoredProperty
459+
else {
460+
return []
461+
}
462+
463+
guard case let .argumentList(arguments) = node.argument,
464+
let firstElement = arguments.first,
465+
let stringLiteral = firstElement.expression
466+
.as(StringLiteralExprSyntax.self),
467+
stringLiteral.segments.count == 1,
468+
case let .stringSegment(wrapperName)? = stringLiteral.segments.first else {
469+
throw CustomError.message("macro requires a string literal containing the name of an attribute")
470+
}
471+
472+
return [
473+
AttributeSyntax(
474+
attributeName: SimpleTypeIdentifierSyntax(
475+
name: .identifier(wrapperName.content.text)
476+
)
477+
)
478+
.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
479+
]
480+
}
481+
}
482+
483+
extension VariableDeclSyntax {
484+
/// Determine whether this variable has the syntax of a stored property.
485+
///
486+
/// This syntactic check cannot account for semantic adjustments due to,
487+
/// e.g., accessor macros or property wrappers.
488+
var isStoredProperty: Bool {
489+
if bindings.count != 1 {
490+
return false
491+
}
492+
493+
let binding = bindings.first!
494+
switch binding.accessor {
495+
case .none:
496+
return true
497+
498+
case .accessors(let node):
499+
for accessor in node.accessors {
500+
switch accessor.accessorKind.tokenKind {
501+
case .keyword(.willSet), .keyword(.didSet):
502+
// Observers can occur on a stored property.
503+
break
504+
505+
default:
506+
// Other accessors make it a computed property.
507+
return false
508+
}
509+
}
510+
511+
return true
512+
513+
case .getter:
514+
return false
515+
516+
@unknown default:
517+
return false
518+
}
519+
}
520+
}
521+
522+
extension DeclGroupSyntax {
523+
/// Enumerate the stored properties that syntactically occur in this
524+
/// declaration.
525+
func storedProperties() -> [VariableDeclSyntax] {
526+
return members.members.compactMap { member in
527+
guard let variable = member.decl.as(VariableDeclSyntax.self),
528+
variable.isStoredProperty else {
529+
return nil
530+
}
531+
532+
return variable
533+
}
534+
}
535+
}

test/Macros/macro_expand_attributes.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
@attached(memberAttribute) macro wrapAllProperties() = #externalMacro(module: "MacroDefinition", type: "WrapAllProperties")
1313

14+
@attached(memberAttribute)
15+
public macro wrapStoredProperties(_ attributeName: String) = #externalMacro(module: "MacroDefinition", type: "WrapStoredPropertiesMacro")
16+
1417
@propertyWrapper
1518
struct Wrapper<T> {
1619
init(wrappedValue: T) {
@@ -99,3 +102,14 @@ _ = c.y
99102
c.x = 10
100103
// CHECK: writing to key-path
101104
c.y = 100
105+
106+
// Use the "wrapStoredProperties" macro to deprecate all of the stored
107+
// properties.
108+
@wrapStoredProperties(#"available(*, deprecated, message: "hands off my data")"#)
109+
struct OldStorage {
110+
var x: Int
111+
}
112+
113+
// The deprecation warning below comes from the deprecation attribute
114+
// introduced by @wrapStoredProperties on OldStorage.
115+
_ = OldStorage(x: 5).x // expected-warning{{'x' is deprecated: hands off my data}}

0 commit comments

Comments
 (0)