-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Macros/Parse] Attributes on MacroExpansionDecl #65815
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
[Macros/Parse] Attributes on MacroExpansionDecl #65815
Conversation
swiftlang/swift-syntax#1650 |
swiftlang/swift-syntax#1650 |
// expected-error@+2 2 {{consecutive declarations on a line must be separated by ';}} | ||
// expected-error@+1 2 {{expected a macro identifier}} | ||
// expected-error@+2 {{consecutive declarations on a line must be separated by ';}} | ||
// expected-error@+1 {{expected a macro identifier}} | ||
/ ###line 25 "line-directive.swift" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is improved because previously #
not followed by an identifier was true
for isStartOfSwiftDecl()
. Now it's false
so the expression parsing recovery skips the second #
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, thank you!
9b92a14
to
9017dea
Compare
swiftlang/swift-syntax#1650 |
lib/Sema/TypeCheckMacros.cpp
Outdated
@@ -1049,8 +1049,10 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) { | |||
|
|||
auto topLevelItems = macroSourceFile->getTopLevelItems(); | |||
for (auto item : topLevelItems) { | |||
if (auto *decl = item.dyn_cast<Decl *>()) | |||
if (auto *decl = item.dyn_cast<Decl *>()) { | |||
decl->getAttrs().add(med->getAttrs()); | |||
decl->setDeclContext(dc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will cause problems when the same attribute is added to multiple places. Per our offline discussion, I think it's best for us to syntactically add the attributes (e.g., by splicing them into the DeclSyntax
nodes we get back from the macro) rather than do it semantically. That way, we'll see the attributes in the expansion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I scoped down this PR to Parse
support only. Removed this bit.
lib/Sema/TypeCheckMacros.cpp
Outdated
@@ -1549,6 +1551,9 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, | |||
macroRef.getArgs(), roles); | |||
} | |||
|
|||
// FIXME: Type checking should reflect the attributes on the expansion. | |||
// e.g. '@available(macOS 999) #Future { newAPIFrom999() }'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual fix for this will be in TypeRefinementContextBuilder
.
// expected-error@+2 2 {{consecutive declarations on a line must be separated by ';}} | ||
// expected-error@+1 2 {{expected a macro identifier}} | ||
// expected-error@+2 {{consecutive declarations on a line must be separated by ';}} | ||
// expected-error@+1 {{expected a macro identifier}} | ||
/ ###line 25 "line-directive.swift" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, thank you!
9017dea
to
74ddec5
Compare
* Parse `#<identifier>` attribute list as a `MacroExpansionDecl` regardless of the position * Diagnose whitespaces between `#` and the macro name. * Correctly attach attributes to `MacroExpansionDecl` * Fix `OrigDeclAttributes` to handle modifiers (use `getLocation()` instead of `AtLoc`.) Type checking is a TODO rdar://107386648
74ddec5
to
9fc1521
Compare
swiftlang/swift-syntax#1650 |
swiftlang/swift-syntax#1650 |
1 similar comment
swiftlang/swift-syntax#1650 |
@@ -4917,7 +4939,8 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) { | |||
// it's an actor declaration, otherwise, it isn't. | |||
do { | |||
consumeToken(); | |||
} while (isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false)); | |||
} while (isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false, | |||
/*hadAttrsOrModifiers=*/true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can actor
be a modifier here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actor
is still declared as a (deprecated) modifier, and it's diagnosed as a error in parseDeclModifierList()
. The diagnostic message is not great, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK. Makes sense then. Just wanted to double-check
@@ -4976,7 +5001,8 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) { | |||
// Otherwise, do a recursive parse. | |||
Parser::BacktrackingScope Backtrack(*this); | |||
consumeToken(tok::identifier); | |||
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false); | |||
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false, | |||
/*hadAttrsOrModifiers=*/true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What’s the attribute or modifier that has been consumed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point Tok
is a contextual keyword, and all decl introducers with contextual keyword (e.g. macro
) are handled above. The all remaining cases are simple decl modifiers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point
Tok
is a contextual keyword
We don’t know that it’s a contextual keyword, right? We just continue pretending that it might be, but really, it could be any identifier, right? Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's
// If this can't possibly be a contextual keyword, then this identifier is
// not interesting. Bail out.
if (!Tok.isContextualDeclKeyword())
return false;
above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK. I just didn’t read far enough back. It’s what you get from large functions that implicitly retain state from other early exits…
Thanks for the explanation. Good with me 👍🏽
if (!isStartOfFreestandingMacroExpansion()) { | ||
consumeToken(tok::pound); | ||
diagnose(Tok.getLoc(), | ||
diag::macro_expansion_expr_expected_macro_identifier); | ||
return makeParserError(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weren’t we diagnosing this before? Out of curiosity: Is there a test case that triggers this?
#<identifier>
after an attribute list as aMacroExpansionDecl
regardless of the position#
and the macro nameMacroExpansionDecl
OrigDeclAttributes
to handle modifiers (usegetLocation()
instead ofAtLoc
.)Type checking and macro expansion are TODO
rdar://107386648