[Macros] Allow keywords after # in freestanding macro expansions

Allow keywords after `#` in freestanding macro expansions

There is no reason why we shouldn’t allow keywords here.

I also thought about allowing keywords after `@` but things become tricky here for two reasons:
- In the parser, we parse a type after the `@`, which could start with a keyword itself (e.g. `any`). If we want to keep the parser logic to parse a type after `@` (which I think we should), then it becomes unclear what `@any T` should parse as.
- We allow a space between `@` and the type name. This makes it very hard for recovery to tell whether `@ struct` refers to an attribute with name `struct` or if the user forgot to write the attribute name after `@`.

Since almost all keywords are lowercase and attached member macros are usually spelled with an uppercase name, there are a lot fewer chances for clashes here, so I don’t think it’s worth allowing keywords after `@`.

https://github.com/apple/swift/issues/66444
rdar://110472060
This commit is contained in:
Alex Hoppen
2023-06-14 13:40:28 -07:00
parent 58ff42af16
commit fbbbd0d08a
6 changed files with 9 additions and 18 deletions

View File

@@ -2301,16 +2301,7 @@ ParserStatus Parser::parseFreestandingMacroExpansion(
bool hasWhitespaceBeforeName = poundEndLoc != Tok.getLoc();
// Diagnose and parse keyword right after `#`.
if (Tok.isKeyword() && !hasWhitespaceBeforeName) {
diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText());
diagnose(Tok, diag::backticks_to_escape)
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
// Let 'parseDeclNameRef' to parse this as an identifier.
Tok.setKind(tok::identifier);
}
macroNameRef = parseDeclNameRef(macroNameLoc, diag, DeclNameOptions());
macroNameRef = parseDeclNameRef(macroNameLoc, diag, DeclNameFlag::AllowKeywords);
if (!macroNameRef)
return makeParserError();

View File

@@ -53,7 +53,7 @@ import MacroLib
@freestanding(expression) public macro `class`() -> Int = #externalMacro(module: "MacroDefinition", type: "OneMacro")
func test() {
let _: Int = #public() // expected-error {{keyword 'public' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}}
let _: Int = #public()
let _: Int = #`public`()
let _: Int = #escaped()
let _: Int = #`class`()

View File

@@ -9,11 +9,11 @@ func sync() {}
macro Self() = #externalMacro(module: "MacroDefinition", type: "InvalidMacro")
func testSelfAsFreestandingMacro() {
_ = #self // expected-error {{keyword 'self' cannot be used as an identifier here}} expected-note {{use backticks to escape it}}
_ = #self
}
func testCapitalSelfAsFreestandingMacro() {
_ = #Self // expected-error {{keyword 'Self' cannot be used as an identifier here}} expected-note {{use backticks to escape it}}
_ = #Self
}
func testSelfAsAttachedMacro() {

View File

@@ -51,6 +51,6 @@ public # someFunc // expected-error {{extraneous whitespace between '#' and macr
struct S {
# someFunc // expected-error {{extraneous whitespace between '#' and macro name is not permitted}} {{4-5=}}
#class // expected-error {{keyword 'class' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}} {{4-9=`class`}}
#class
# struct Inner {} // expected-error {{expected a macro identifier for a pound literal declaration}} expected-error {{consecutive declarations on a line}}
}

View File

@@ -44,7 +44,7 @@ do {
_ = # macro() // expected-error {{extraneous whitespace between '#' and macro name is not permitted}} {{8-9=}}
}
do {
_ = #public() // expected-error {{keyword 'public' cannot be used as an identifier here}} expected-note {{if this name is unavoidable, use backticks to escape it}} {{8-14=`public`}}
_ = #public()
}
do {
_ = # public() // expected-error {{expected a macro identifier for a pound literal expression}}

View File

@@ -35,9 +35,9 @@ import func Swift.print
// rdar://14418336
#import something_nonexistent
// expected-error@-1 {{keyword 'import' cannot be used as an identifier here}} expected-note@-1 {{use backticks to escape it}}
// expected-error@-2 {{no macro named 'import'}}
// expected-error@-3 {{consecutive statements on a line}} expected-error@-3 {{cannot find 'something_nonexistent' in scope}}
// expected-error@-1 {{no macro named 'import'}}
// expected-error@-2 {{consecutive statements on a line}}
// expected-error@-3 {{cannot find 'something_nonexistent' in scope}}
// Import specific decls
import typealias Swift.Int