Skip to content

Commit 8533073

Browse files
committed
[Parse] Disallow space between attribute name and '(' in Swift 6 mode
This allows us to resolve disambiguities of whether a parenthesis belong to an argument to the attribute or if it is eg. the start of a tuple.
1 parent cc5e79b commit 8533073

File tree

5 files changed

+95
-40
lines changed

5 files changed

+95
-40
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,9 @@ ERROR(decl_attribute_applied_to_type,none,
15141514
ERROR(attr_extra_whitespace_after_at,PointsToFirstBadToken,
15151515
"extraneous whitespace between '@' and attribute name", ())
15161516

1517+
ERROR(attr_extra_whitespace_before_lparen,PointsToFirstBadToken,
1518+
"extraneous whitespace between attribute name and '('", ())
1519+
15171520
ERROR(attr_expected_lparen,none,
15181521
"expected '(' in '%0' %select{attribute|modifier}1", (StringRef, bool))
15191522

include/swift/Parse/Parser.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,18 @@ class Parser {
602602
return true;
603603
}
604604

605+
/// Consume a '('. If it is not directly following the previous token, emit an
606+
/// error (Swift 6) or warning (Swift <6) that attribute name and parentheses
607+
/// must not be separated by a space.
608+
SourceLoc consumeAttributeLParen();
609+
610+
/// If the next token is a '(' that's not on a new line consume it, and error
611+
/// (Swift 6) or warn (Swift <6) that the attribute must not be separted from
612+
/// the '(' by a space.
613+
///
614+
/// If the next token is not '(' or it's on a new line, return false.
615+
bool consumeIfAttributeLParen();
616+
605617
bool consumeIfNotAtStartOfLine(tok K) {
606618
if (Tok.isAtStartOfLine()) return false;
607619
return consumeIf(K);

lib/Parse/ParseDecl.cpp

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ bool Parser::parseSpecializeAttribute(
10931093
llvm::function_ref<bool(Parser &)> parseSILSIPModule) {
10941094
assert(ClosingBrace == tok::r_paren || ClosingBrace == tok::r_square);
10951095

1096-
SourceLoc lParenLoc = consumeToken();
1096+
SourceLoc lParenLoc = consumeAttributeLParen();
10971097
bool DiscardAttribute = false;
10981098
StringRef AttrName = "_specialize";
10991099

@@ -1157,7 +1157,7 @@ Parser::parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
11571157
}
11581158

11591159
// Consume '('
1160-
SourceLoc lParenLoc = consumeToken();
1160+
SourceLoc lParenLoc = consumeAttributeLParen();
11611161

11621162
SmallVector<Identifier> initializesProperties;
11631163
SmallVector<Identifier> accessesProperties;
@@ -1319,7 +1319,7 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
13191319
return Status;
13201320
}
13211321

1322-
SourceLoc lParenLoc = consumeToken();
1322+
SourceLoc lParenLoc = consumeAttributeLParen();
13231323

13241324
DeclNameLoc MemberNameLoc;
13251325
DeclNameRef MemberName;
@@ -1379,13 +1379,13 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
13791379
ParserResult<DifferentiableAttr>
13801380
Parser::parseDifferentiableAttribute(SourceLoc atLoc, SourceLoc loc) {
13811381
StringRef AttrName = "differentiable";
1382-
SourceLoc lParenLoc = loc, rParenLoc = loc;
1382+
SourceLoc rParenLoc = loc;
13831383
DifferentiabilityKind diffKind = DifferentiabilityKind::Normal;
13841384
SmallVector<ParsedAutoDiffParameter, 8> parameters;
13851385
TrailingWhereClause *whereClause = nullptr;
13861386

13871387
// Parse '('.
1388-
if (consumeIf(tok::l_paren, lParenLoc)) {
1388+
if (consumeIfAttributeLParen()) {
13891389
// Parse @differentiable attribute arguments.
13901390
if (parseDifferentiableAttributeArguments(
13911391
diffKind, parameters, whereClause))
@@ -1415,7 +1415,7 @@ bool Parser::parseExternAttribute(DeclAttributes &Attributes,
14151415
SourceLoc lParenLoc = Tok.getLoc(), rParenLoc;
14161416

14171417
// Parse @_extern(<language>, ...)
1418-
if (!consumeIf(tok::l_paren)) {
1418+
if (!consumeIfAttributeLParen()) {
14191419
diagnose(Loc, diag::attr_expected_lparen, AttrName,
14201420
DeclAttribute::isDeclModifier(DAK_Extern));
14211421
return false;
@@ -1857,7 +1857,7 @@ static bool parseQualifiedDeclName(Parser &P, Diag<> nameParseError,
18571857
ParserResult<DerivativeAttr> Parser::parseDerivativeAttribute(SourceLoc atLoc,
18581858
SourceLoc loc) {
18591859
StringRef AttrName = "derivative";
1860-
SourceLoc lParenLoc = loc, rParenLoc = loc;
1860+
SourceLoc rParenLoc = loc;
18611861
TypeRepr *baseType = nullptr;
18621862
DeclNameRefWithLoc original;
18631863
SmallVector<ParsedAutoDiffParameter, 8> parameters;
@@ -1885,7 +1885,7 @@ ParserResult<DerivativeAttr> Parser::parseDerivativeAttribute(SourceLoc atLoc,
18851885
return errorAndSkipUntilConsumeRightParen(*this, AttrName);
18861886
};
18871887
// Parse '('.
1888-
if (!consumeIf(tok::l_paren, lParenLoc)) {
1888+
if (!consumeIfAttributeLParen()) {
18891889
diagnose(getEndOfPreviousLoc(), diag::attr_expected_lparen, AttrName,
18901890
/*DeclModifier*/ false);
18911891
return makeParserError();
@@ -1937,7 +1937,7 @@ ParserResult<DerivativeAttr> Parser::parseDerivativeAttribute(SourceLoc atLoc,
19371937
ParserResult<TransposeAttr> Parser::parseTransposeAttribute(SourceLoc atLoc,
19381938
SourceLoc loc) {
19391939
StringRef AttrName = "transpose";
1940-
SourceLoc lParenLoc = loc, rParenLoc = loc;
1940+
SourceLoc rParenLoc = loc;
19411941
TypeRepr *baseType = nullptr;
19421942
DeclNameRefWithLoc original;
19431943
SmallVector<ParsedAutoDiffParameter, 8> parameters;
@@ -1966,7 +1966,7 @@ ParserResult<TransposeAttr> Parser::parseTransposeAttribute(SourceLoc atLoc,
19661966
};
19671967

19681968
// Parse '('.
1969-
if (!consumeIf(tok::l_paren, lParenLoc)) {
1969+
if (!consumeIfAttributeLParen()) {
19701970
diagnose(getEndOfPreviousLoc(), diag::attr_expected_lparen, AttrName,
19711971
/*DeclModifier*/ false);
19721972
return makeParserError();
@@ -2270,7 +2270,7 @@ bool Parser::parseBackDeployedAttribute(DeclAttributes &Attributes,
22702270
SourceLoc Loc) {
22712271
std::string AtAttrName = (llvm::Twine("@") + AttrName).str();
22722272
auto LeftLoc = Tok.getLoc();
2273-
if (!consumeIf(tok::l_paren)) {
2273+
if (!consumeIfAttributeLParen()) {
22742274
diagnose(Loc, diag::attr_expected_lparen, AtAttrName,
22752275
DeclAttribute::isDeclModifier(DAK_BackDeployed));
22762276
return false;
@@ -2418,7 +2418,7 @@ Parser::parseDocumentationAttribute(SourceLoc AtLoc, SourceLoc Loc) {
24182418
llvm::Optional<AccessLevel> Visibility = llvm::None;
24192419
llvm::Optional<StringRef> Metadata = llvm::None;
24202420

2421-
if (!consumeIf(tok::l_paren)) {
2421+
if (!consumeIfAttributeLParen()) {
24222422
diagnose(Loc, diag::attr_expected_lparen, AttrName,
24232423
declModifier);
24242424
return makeParserError();
@@ -2503,7 +2503,7 @@ Parser::parseMacroRoleAttribute(
25032503
}
25042504

25052505
// Parse the argments.
2506-
SourceLoc lParenLoc = consumeToken();
2506+
SourceLoc lParenLoc = consumeAttributeLParen();
25072507
SourceLoc rParenLoc;
25082508
llvm::Optional<MacroRole> role;
25092509
bool sawRole = false;
@@ -2750,7 +2750,7 @@ static llvm::Optional<Identifier> parseSingleAttrOptionImpl(
27502750
return llvm::None;
27512751
}
27522752

2753-
P.consumeToken(tok::l_paren);
2753+
P.consumeAttributeLParen();
27542754

27552755
StringRef parsedName = P.Tok.getText();
27562756
if (!P.consumeIf(tok::identifier)) {
@@ -2913,7 +2913,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
29132913
break;
29142914

29152915
case DAK_Effects: {
2916-
if (!consumeIf(tok::l_paren)) {
2916+
if (!consumeIfAttributeLParen()) {
29172917
diagnose(Loc, diag::attr_expected_lparen, AttrName,
29182918
DeclAttribute::isDeclModifier(DK));
29192919
return makeParserSuccess();
@@ -3093,7 +3093,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
30933093
break;
30943094
}
30953095

3096-
consumeToken(tok::l_paren);
3096+
consumeAttributeLParen();
30973097

30983098
// Parse the subject.
30993099
if (Tok.isContextualKeyword("set")) {
@@ -3145,7 +3145,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
31453145
}
31463146

31473147
case DAK_SPIAccessControl: {
3148-
if (!consumeIf(tok::l_paren)) {
3148+
if (!consumeIfAttributeLParen()) {
31493149
diagnose(Loc, diag::attr_expected_lparen, AttrName,
31503150
DeclAttribute::isDeclModifier(DK));
31513151
return makeParserSuccess();
@@ -3186,7 +3186,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
31863186
case DAK_CDecl:
31873187
case DAK_Expose:
31883188
case DAK_SILGenName: {
3189-
if (!consumeIf(tok::l_paren)) {
3189+
if (!consumeIfAttributeLParen()) {
31903190
diagnose(Loc, diag::attr_expected_lparen, AttrName,
31913191
DeclAttribute::isDeclModifier(DK));
31923192
return makeParserSuccess();
@@ -3293,7 +3293,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
32933293
}
32943294

32953295
case DAK_Section: {
3296-
if (!consumeIf(tok::l_paren)) {
3296+
if (!consumeIfAttributeLParen()) {
32973297
diagnose(Loc, diag::attr_expected_lparen, AttrName,
32983298
DeclAttribute::isDeclModifier(DK));
32993299
return makeParserSuccess();
@@ -3333,12 +3333,12 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
33333333
}
33343334

33353335
case DAK_Alignment: {
3336-
if (!consumeIf(tok::l_paren)) {
3336+
if (!consumeIfAttributeLParen()) {
33373337
diagnose(Loc, diag::attr_expected_lparen, AttrName,
33383338
DeclAttribute::isDeclModifier(DK));
33393339
return makeParserSuccess();
33403340
}
3341-
3341+
33423342
if (Tok.isNot(tok::integer_literal)) {
33433343
diagnose(Loc, diag::alignment_must_be_positive_integer);
33443344
return makeParserSuccess();
@@ -3380,7 +3380,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
33803380
}
33813381

33823382
case DAK_Semantics: {
3383-
if (!consumeIf(tok::l_paren)) {
3383+
if (!consumeIfAttributeLParen()) {
33843384
diagnose(Loc, diag::attr_expected_lparen, AttrName,
33853385
DeclAttribute::isDeclModifier(DK));
33863386
return makeParserSuccess();
@@ -3415,7 +3415,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
34153415
}
34163416
case DAK_OriginallyDefinedIn: {
34173417
auto LeftLoc = Tok.getLoc();
3418-
if (!consumeIf(tok::l_paren)) {
3418+
if (!consumeIfAttributeLParen()) {
34193419
diagnose(Loc, diag::attr_expected_lparen, AttrName,
34203420
DeclAttribute::isDeclModifier(DK));
34213421
return makeParserSuccess();
@@ -3505,7 +3505,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
35053505
break;
35063506
}
35073507
case DAK_Available: {
3508-
if (!consumeIf(tok::l_paren)) {
3508+
if (!consumeIfAttributeLParen()) {
35093509
diagnose(Loc, diag::attr_expected_lparen, AttrName,
35103510
DeclAttribute::isDeclModifier(DK));
35113511
return makeParserSuccess();
@@ -3523,7 +3523,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
35233523
DeclAttribute::isDeclModifier(DK));
35243524
return makeParserSuccess();
35253525
}
3526-
SourceLoc LParenLoc = consumeToken(tok::l_paren);
3526+
SourceLoc LParenLoc = consumeAttributeLParen();
35273527
llvm::Optional<StringRef> filename;
35283528
{
35293529
// Parse 'sourceFile'.
@@ -3574,7 +3574,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
35743574
}
35753575

35763576
// Parse the leading '('.
3577-
SourceLoc LParenLoc = consumeToken(tok::l_paren);
3577+
SourceLoc LParenLoc = consumeAttributeLParen();
35783578

35793579
// Parse the names, with trailing colons (if there are present) and populate
35803580
// the inout parameters
@@ -3640,7 +3640,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
36403640
return makeParserSuccess();
36413641
}
36423642

3643-
SourceLoc LParenLoc = consumeToken(tok::l_paren);
3643+
SourceLoc LParenLoc = consumeAttributeLParen();
36443644
DeclNameRef replacedFunction;
36453645
{
36463646
// Parse 'for'.
@@ -3691,7 +3691,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
36913691
return makeParserSuccess();
36923692
}
36933693

3694-
SourceLoc LParenLoc = consumeToken(tok::l_paren);
3694+
SourceLoc LParenLoc = consumeAttributeLParen();
36953695
ParserResult<TypeRepr> ErasedType;
36963696
bool invalid = false;
36973697
{
@@ -3792,7 +3792,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
37923792

37933793
case DAK_UnavailableFromAsync: {
37943794
StringRef message;
3795-
if (consumeIf(tok::l_paren)) {
3795+
if (consumeIfAttributeLParen()) {
37963796
if (!Tok.is(tok::identifier)) {
37973797
llvm_unreachable("Flag must start with an identifier");
37983798
}
@@ -3882,7 +3882,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
38823882
return makeParserSuccess();
38833883
}
38843884

3885-
consumeToken(tok::l_paren);
3885+
consumeAttributeLParen();
38863886

38873887
if (!Tok.canBeArgumentLabel()) {
38883888
diagnose(Loc, diag::attr_rawlayout_expected_label, "'size', 'like', or 'likeArrayOf'");
@@ -4160,6 +4160,10 @@ ParserResult<CustomAttr> Parser::parseCustomAttribute(
41604160

41614161
initParser.emplace(*this, initContext);
41624162
}
4163+
if (getEndOfPreviousLoc() != Tok.getLoc()) {
4164+
diagnose(getEndOfPreviousLoc(), diag::attr_extra_whitespace_before_lparen)
4165+
.warnUntilSwiftVersion(6);
4166+
}
41634167
auto result = parseArgumentList(tok::l_paren, tok::r_paren,
41644168
/*isExprBasic*/ true,
41654169
/*allowTrailingClosure*/ false);
@@ -4427,10 +4431,11 @@ static bool parseDifferentiableTypeAttributeArgument(
44274431
SourceLoc &diffKindLocResult, bool emitDiagnostics) {
44284432
Parser::CancellableBacktrackingScope backtrack(P);
44294433

4430-
SourceLoc beginLoc, kindLoc, endLoc;
4434+
SourceLoc beginLoc = P.Tok.getLoc();
4435+
SourceLoc kindLoc, endLoc;
44314436

44324437
// Match '( <identifier> )', and store the identifier token to `argument`.
4433-
if (!P.consumeIf(tok::l_paren, beginLoc))
4438+
if (!P.consumeIfAttributeLParen())
44344439
return false;
44354440
auto argument = P.Tok;
44364441
if (!P.consumeIf(tok::identifier, kindLoc))
@@ -4498,7 +4503,7 @@ bool Parser::parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc
44984503
ConventionTypeAttr *&result,
44994504
bool justChecking) {
45004505
SourceLoc LPLoc = Tok.getLoc();
4501-
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
4506+
if (!consumeIfAttributeLParen()) {
45024507
if (!justChecking)
45034508
diagnose(Tok, diag::convention_attribute_expected_lparen);
45044509
return true;
@@ -4764,7 +4769,7 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
47644769
case TAK_opened: {
47654770
// Parse the opened existential ID string in parens
47664771
SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc;
4767-
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
4772+
if (!consumeAttributeLParen()) {
47684773
if (!justChecking)
47694774
diagnose(Tok, diag::opened_attribute_expected_lparen);
47704775
return makeParserError();
@@ -4817,7 +4822,7 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
48174822

48184823
// Parse the opened ID string in parens
48194824
SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc;
4820-
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
4825+
if (!consumeIfAttributeLParen()) {
48214826
if (!justChecking)
48224827
diagnose(Tok, diag::pack_element_attribute_expected_lparen);
48234828
return makeParserError();
@@ -4892,12 +4897,12 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
48924897
case TAK__opaqueReturnTypeOf: {
48934898
// Parse the mangled decl name and index.
48944899
auto beginLoc = Tok.getLoc();
4895-
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
4900+
if (!consumeIfAttributeLParen()) {
48964901
if (!justChecking)
48974902
diagnose(Tok, diag::attr_expected_lparen, "_opaqueReturnTypeOf", false);
48984903
return makeParserError();
48994904
}
4900-
4905+
49014906
if (!Tok.is(tok::string_literal)) {
49024907
if (!justChecking)
49034908
diagnose(Tok, diag::opened_attribute_id_value);

lib/Parse/Parser.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,23 @@ SourceLoc Parser::getEndOfPreviousLoc() const {
576576
return Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc);
577577
}
578578

579+
SourceLoc Parser::consumeAttributeLParen() {
580+
SourceLoc LastTokenEndLoc = getEndOfPreviousLoc();
581+
if (LastTokenEndLoc != Tok.getLoc()) {
582+
diagnose(LastTokenEndLoc, diag::attr_extra_whitespace_before_lparen)
583+
.warnUntilSwiftVersion(6);
584+
}
585+
return consumeToken(tok::l_paren);
586+
}
587+
588+
bool Parser::consumeIfAttributeLParen() {
589+
if (!Tok.isFollowingLParen()) {
590+
return false;
591+
}
592+
consumeAttributeLParen();
593+
return true;
594+
}
595+
579596
SourceLoc Parser::consumeStartingCharacterOfCurrentToken(tok Kind, size_t Len) {
580597
// Consumes prefix of token and returns its location.
581598
// (like '?', '<', '>' or '!' immediately followed by '<')

0 commit comments

Comments
 (0)