diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 58ef352b0a138..c0d4dd345dc72 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -62,7 +62,7 @@ ERROR(pound_diagnostic_expected_string,none, "expected string literal in %select{#warning|#error}0 directive",(bool)) ERROR(pound_diagnostic_expected,none, "expected '%0' in %select{#warning|#error}1 directive",(StringRef,bool)) -ERROR(pound_diagnostic_expected_parens,none, +ERROR(pound_diagnostic_expected_parens,PointsToFirstBadToken, "%select{#warning|#error}0 directive requires parentheses",(bool)) ERROR(pound_diagnostic_interpolation,none, "string interpolation is not allowed in %select{#warning|#error}0 directives",(bool)) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 78de6ddde3484..689914066574f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2503,7 +2503,7 @@ static std::optional parseSingleAttrOptionImpl( }; bool isDeclModifier = DeclAttribute::isDeclModifier(DK); - if (!P.Tok.is(tok::l_paren)) { + if (!P.Tok.isFollowingLParen()) { if (allowOmitted) return Identifier(); @@ -2883,7 +2883,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, .Case("public", AccessLevel::Public) .Case("open", AccessLevel::Open); - if (!Tok.is(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { // Normal access control attribute. AttrRange = Loc; @@ -3443,7 +3443,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, } case DeclAttrKind::PrivateImport: { // Parse the leading '('. - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); @@ -3492,7 +3492,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, } case DeclAttrKind::ObjC: { // Unnamed @objc attribute. - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { auto attr = ObjCAttr::createUnnamed(Context, AtLoc, Loc); Attributes.add(attr); break; @@ -3560,7 +3560,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, case DeclAttrKind::DynamicReplacement: { // Parse the leading '('. - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); @@ -3611,7 +3611,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, case DeclAttrKind::TypeEraser: { // Parse leading '(' - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); @@ -3641,7 +3641,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, case DeclAttrKind::Specialize: case DeclAttrKind::Specialized: { - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); @@ -3870,7 +3870,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, break; } case DeclAttrKind::RawLayout: { - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(Loc, diag::attr_expected_lparen, AttrName, DeclAttribute::isDeclModifier(DK)); return makeParserSuccess(); @@ -4172,7 +4172,7 @@ ParserResult Parser::parseCustomAttribute(SourceLoc atLoc) { // Parse a custom attribute. auto type = parseType(diag::expected_type, ParseTypeReason::CustomAttribute); if (type.hasCodeCompletion() || type.isNull()) { - if (Tok.is(tok::l_paren) && isCustomAttributeArgument()) + if (Tok.isFollowingLParen() && isCustomAttributeArgument()) skipSingle(); return ParserResult(ParserStatus(type)); @@ -4354,7 +4354,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc attrLoc = consumeToken(); // @warn_unused_result with no arguments. - if (Tok.isNot(tok::l_paren)) { + if (!Tok.isFollowingLParen()) { diagnose(AtLoc, diag::attr_warn_unused_result_removed) .fixItRemove(SourceRange(AtLoc, attrLoc)); @@ -4438,7 +4438,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, // Recover by eating @foo(...) when foo is not known. consumeToken(); - if (Tok.is(tok::l_paren)) + if (Tok.isFollowingLParen()) skipSingle(); return makeParserError(); @@ -5910,7 +5910,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes, // If it might be, we do some more digging. // If this is 'unowned', check to see if it is valid. - if (Tok.getText() == "unowned" && Tok2.is(tok::l_paren)) { + if (Tok.getText() == "unowned" && Tok2.isFollowingLParen()) { Parser::BacktrackingScope Backtrack(*this); if (consumeIfParenthesizedUnowned(*this)) { return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false, @@ -5919,7 +5919,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes, } // If this is 'nonisolated', check to see if it is valid. - if (Tok.isContextualKeyword("nonisolated") && Tok2.is(tok::l_paren)) { + if (Tok.isContextualKeyword("nonisolated") && Tok2.isFollowingLParen()) { BacktrackingScope backtrack(*this); if (consumeIfParenthesizedNonisolated(*this)) { return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false, @@ -7262,6 +7262,12 @@ ParserStatus Parser::parseDeclPoundDiagnostic() { bool isError = Tok.is(tok::pound_error); consumeToken(isError ? tok::pound_error : tok::pound_warning); + if (Tok.isAtStartOfLine()) { + diagnose(Tok, diag::pound_diagnostic_expected_parens, isError) + .fixItInsertAfter(PreviousLoc, "(\"<#message#>\")"); + return makeParserSuccess(); + } + SourceLoc lParenLoc = Tok.getLoc(); bool hadLParen = consumeIf(tok::l_paren); @@ -7358,7 +7364,7 @@ ParserStatus Parser::parseLineDirective(bool isLine) { unsigned StartLine = 0; std::optional Filename; - if (!isLine) { + if (!isLine && !Tok.isAtStartOfLine()) { // #sourceLocation() // #sourceLocation(file: "foo", line: 42) if (parseToken(tok::l_paren, diag::sourceLocation_expected, "(")) diff --git a/test/Parse/attribute_spacing.swift b/test/Parse/attribute_spacing.swift index e759f4132cad2..337b698c2be81 100644 --- a/test/Parse/attribute_spacing.swift +++ b/test/Parse/attribute_spacing.swift @@ -18,6 +18,10 @@ struct MyPropertyWrapper { struct PropertyWrapperTest { @MyPropertyWrapper (param: 2) // expected-warning {{extraneous whitespace between attribute name and '('; this is an error in the Swift 6 language mode}} var x: Int + + @MyPropertyWrapper + (param: 2) // expected-error {{expected 'var' keyword in property declaration}} expected-error {{property declaration does not bind any variables}} expected-error {{expected pattern}} + var y: Int } 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 @ MainActor func mainActorFunc() {} + + +@inline // expected-error {{expected '(' in 'inline' attribute}} +(never) func neverInline() {} // expected-error {{expected declaration}} + +@objc +(whatever) func whateverObjC() {} // expected-error {{expected declaration}} diff --git a/test/Parse/line-directive.swift b/test/Parse/line-directive.swift index f6080333746a4..4d3dde1c44e4a 100644 --- a/test/Parse/line-directive.swift +++ b/test/Parse/line-directive.swift @@ -84,3 +84,6 @@ class I55049 { // expected-error@+1 {{#line directive was renamed to #sourceLocation}} #line 1_000 "issue-55049.swift" class I55049_1 {} + +#sourceLocation +(file: "nextLine.swift", line: 400) // expected-warning {{expression of type '(file: String, line: Int)' is unused}} diff --git a/test/Sema/pound_diagnostics.swift b/test/Sema/pound_diagnostics.swift index c4cf8d435bc3c..bf1462d608292 100644 --- a/test/Sema/pound_diagnostics.swift +++ b/test/Sema/pound_diagnostics.swift @@ -82,3 +82,6 @@ protocol MyProtocol { """) // expected-warning @-2 {{warnings support multi-line string literals}} #warning(#"warnings support \(custom string delimiters)"#) // expected-warning {{warnings support \\(custom string delimiters)}} + +#warning // expected-error {{#warning directive requires parentheses}} {{9-9=("<#message#>")}} +("message") // expected-warning {{string literal is unused}}