Skip to content

Commit b271766

Browse files
committed
[Parse] Ignore '(' on newline after attribute names
Also '#error', '#warning', and '#sourceLocation'. Other call-like syntax (call expression, macro expansion, and custom attribtues) requires '(' on the same line as the callee. For consistency, built-in attributes and built-in directives should also ignore '(' on next line.
1 parent 3195c28 commit b271766

File tree

5 files changed

+38
-15
lines changed

5 files changed

+38
-15
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ ERROR(pound_diagnostic_expected_string,none,
6262
"expected string literal in %select{#warning|#error}0 directive",(bool))
6363
ERROR(pound_diagnostic_expected,none,
6464
"expected '%0' in %select{#warning|#error}1 directive",(StringRef,bool))
65-
ERROR(pound_diagnostic_expected_parens,none,
65+
ERROR(pound_diagnostic_expected_parens,PointsToFirstBadToken,
6666
"%select{#warning|#error}0 directive requires parentheses",(bool))
6767
ERROR(pound_diagnostic_interpolation,none,
6868
"string interpolation is not allowed in %select{#warning|#error}0 directives",(bool))

lib/Parse/ParseDecl.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,7 +2503,7 @@ static std::optional<Identifier> parseSingleAttrOptionImpl(
25032503
};
25042504
bool isDeclModifier = DeclAttribute::isDeclModifier(DK);
25052505

2506-
if (!P.Tok.is(tok::l_paren)) {
2506+
if (!P.Tok.isFollowingLParen()) {
25072507
if (allowOmitted)
25082508
return Identifier();
25092509

@@ -2883,7 +2883,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
28832883
.Case("public", AccessLevel::Public)
28842884
.Case("open", AccessLevel::Open);
28852885

2886-
if (!Tok.is(tok::l_paren)) {
2886+
if (!Tok.isFollowingLParen()) {
28872887
// Normal access control attribute.
28882888
AttrRange = Loc;
28892889

@@ -3443,7 +3443,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
34433443
}
34443444
case DeclAttrKind::PrivateImport: {
34453445
// Parse the leading '('.
3446-
if (Tok.isNot(tok::l_paren)) {
3446+
if (!Tok.isFollowingLParen()) {
34473447
diagnose(Loc, diag::attr_expected_lparen, AttrName,
34483448
DeclAttribute::isDeclModifier(DK));
34493449
return makeParserSuccess();
@@ -3492,7 +3492,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
34923492
}
34933493
case DeclAttrKind::ObjC: {
34943494
// Unnamed @objc attribute.
3495-
if (Tok.isNot(tok::l_paren)) {
3495+
if (!Tok.isFollowingLParen()) {
34963496
auto attr = ObjCAttr::createUnnamed(Context, AtLoc, Loc);
34973497
Attributes.add(attr);
34983498
break;
@@ -3560,7 +3560,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
35603560

35613561
case DeclAttrKind::DynamicReplacement: {
35623562
// Parse the leading '('.
3563-
if (Tok.isNot(tok::l_paren)) {
3563+
if (!Tok.isFollowingLParen()) {
35643564
diagnose(Loc, diag::attr_expected_lparen, AttrName,
35653565
DeclAttribute::isDeclModifier(DK));
35663566
return makeParserSuccess();
@@ -3611,7 +3611,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
36113611

36123612
case DeclAttrKind::TypeEraser: {
36133613
// Parse leading '('
3614-
if (Tok.isNot(tok::l_paren)) {
3614+
if (!Tok.isFollowingLParen()) {
36153615
diagnose(Loc, diag::attr_expected_lparen, AttrName,
36163616
DeclAttribute::isDeclModifier(DK));
36173617
return makeParserSuccess();
@@ -3641,7 +3641,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
36413641

36423642
case DeclAttrKind::Specialize:
36433643
case DeclAttrKind::Specialized: {
3644-
if (Tok.isNot(tok::l_paren)) {
3644+
if (!Tok.isFollowingLParen()) {
36453645
diagnose(Loc, diag::attr_expected_lparen, AttrName,
36463646
DeclAttribute::isDeclModifier(DK));
36473647
return makeParserSuccess();
@@ -3870,7 +3870,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
38703870
break;
38713871
}
38723872
case DeclAttrKind::RawLayout: {
3873-
if (Tok.isNot(tok::l_paren)) {
3873+
if (!Tok.isFollowingLParen()) {
38743874
diagnose(Loc, diag::attr_expected_lparen, AttrName,
38753875
DeclAttribute::isDeclModifier(DK));
38763876
return makeParserSuccess();
@@ -4172,7 +4172,7 @@ ParserResult<CustomAttr> Parser::parseCustomAttribute(SourceLoc atLoc) {
41724172
// Parse a custom attribute.
41734173
auto type = parseType(diag::expected_type, ParseTypeReason::CustomAttribute);
41744174
if (type.hasCodeCompletion() || type.isNull()) {
4175-
if (Tok.is(tok::l_paren) && isCustomAttributeArgument())
4175+
if (Tok.isFollowingLParen() && isCustomAttributeArgument())
41764176
skipSingle();
41774177

41784178
return ParserResult<CustomAttr>(ParserStatus(type));
@@ -4354,7 +4354,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
43544354
SourceLoc attrLoc = consumeToken();
43554355

43564356
// @warn_unused_result with no arguments.
4357-
if (Tok.isNot(tok::l_paren)) {
4357+
if (!Tok.isFollowingLParen()) {
43584358
diagnose(AtLoc, diag::attr_warn_unused_result_removed)
43594359
.fixItRemove(SourceRange(AtLoc, attrLoc));
43604360

@@ -4438,7 +4438,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
44384438

44394439
// Recover by eating @foo(...) when foo is not known.
44404440
consumeToken();
4441-
if (Tok.is(tok::l_paren))
4441+
if (Tok.isFollowingLParen())
44424442
skipSingle();
44434443

44444444
return makeParserError();
@@ -5910,7 +5910,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
59105910
// If it might be, we do some more digging.
59115911

59125912
// If this is 'unowned', check to see if it is valid.
5913-
if (Tok.getText() == "unowned" && Tok2.is(tok::l_paren)) {
5913+
if (Tok.getText() == "unowned" && Tok2.isFollowingLParen()) {
59145914
Parser::BacktrackingScope Backtrack(*this);
59155915
if (consumeIfParenthesizedUnowned(*this)) {
59165916
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
@@ -5919,7 +5919,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes,
59195919
}
59205920

59215921
// If this is 'nonisolated', check to see if it is valid.
5922-
if (Tok.isContextualKeyword("nonisolated") && Tok2.is(tok::l_paren)) {
5922+
if (Tok.isContextualKeyword("nonisolated") && Tok2.isFollowingLParen()) {
59235923
BacktrackingScope backtrack(*this);
59245924
if (consumeIfParenthesizedNonisolated(*this)) {
59255925
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false,
@@ -7262,6 +7262,12 @@ ParserStatus Parser::parseDeclPoundDiagnostic() {
72627262
bool isError = Tok.is(tok::pound_error);
72637263
consumeToken(isError ? tok::pound_error : tok::pound_warning);
72647264

7265+
if (Tok.isAtStartOfLine()) {
7266+
diagnose(Tok, diag::pound_diagnostic_expected_parens, isError)
7267+
.fixItInsertAfter(PreviousLoc, "(\"<#message#>\")");
7268+
return makeParserSuccess();
7269+
}
7270+
72657271
SourceLoc lParenLoc = Tok.getLoc();
72667272
bool hadLParen = consumeIf(tok::l_paren);
72677273

@@ -7358,7 +7364,7 @@ ParserStatus Parser::parseLineDirective(bool isLine) {
73587364

73597365
unsigned StartLine = 0;
73607366
std::optional<StringRef> Filename;
7361-
if (!isLine) {
7367+
if (!isLine && !Tok.isAtStartOfLine()) {
73627368
// #sourceLocation()
73637369
// #sourceLocation(file: "foo", line: 42)
73647370
if (parseToken(tok::l_paren, diag::sourceLocation_expected, "("))

test/Parse/attribute_spacing.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ struct MyPropertyWrapper {
1818
struct PropertyWrapperTest {
1919
@MyPropertyWrapper (param: 2) // expected-warning {{extraneous whitespace between attribute name and '('; this is an error in the Swift 6 language mode}}
2020
var x: Int
21+
22+
@MyPropertyWrapper
23+
(param: 2) // expected-error {{expected 'var' keyword in property declaration}} expected-error {{property declaration does not bind any variables}} expected-error {{expected pattern}}
24+
var y: Int
2125
}
2226

2327
let closure1 = { @MainActor (a, b) in // expected-warning {{extraneous whitespace between attribute name and '('; this is an error in the Swift 6 language mode}}
@@ -31,3 +35,10 @@ let closure2 = { @MainActor
3135
@
3236
MainActor
3337
func mainActorFunc() {}
38+
39+
40+
@inline // expected-error {{expected '(' in 'inline' attribute}}
41+
(never) func neverInline() {} // expected-error {{expected declaration}}
42+
43+
@objc
44+
(whatever) func whateverObjC() {} // expected-error {{expected declaration}}

test/Parse/line-directive.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@ class I55049 {
8484
// expected-error@+1 {{#line directive was renamed to #sourceLocation}}
8585
#line 1_000 "issue-55049.swift"
8686
class I55049_1 {}
87+
88+
#sourceLocation
89+
(file: "nextLine.swift", line: 400) // expected-warning {{expression of type '(file: String, line: Int)' is unused}}

test/Sema/pound_diagnostics.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,6 @@ protocol MyProtocol {
8282
""") // expected-warning @-2 {{warnings support multi-line string literals}}
8383
8484
#warning(#"warnings support \(custom string delimiters)"#) // expected-warning {{warnings support \\(custom string delimiters)}}
85+
86+
#warning // expected-error {{#warning directive requires parentheses}} {{9-9=("<#message#>")}}
87+
("message") // expected-warning {{string literal is unused}}

0 commit comments

Comments
 (0)