https://github.com/nehaGautam07 updated https://github.com/llvm/llvm-project/pull/220259
>From a68ba345063247506807acaf2990ba1fc4aa749e Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Sat, 5 Sep 2026 11:52:10 +0000 Subject: [PATCH 1/7] [Clang][Parser] Reject unbalanced unknown attribute arguments --- clang/include/clang/Parse/Parser.h | 4 +++- clang/lib/Parse/ParseDeclCXX.cpp | 5 ++++- clang/lib/Parse/Parser.cpp | 6 ++++++ clang/test/Parser/cxx11-unbalanced-attr-args.cpp | 7 +++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Parser/cxx11-unbalanced-attr-args.cpp diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ae91153e34e3a..4a1b330fc995e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -570,7 +570,9 @@ class Parser : public CodeCompletionHandler { StopAtSemi = 1 << 0, ///< Stop skipping at semicolon /// Stop skipping at specified token, but don't skip the token itself StopBeforeMatch = 1 << 1, - StopAtCodeCompletion = 1 << 2 ///< Stop at code completion + StopAtCodeCompletion = 1 << 2, ///< Stop at code completion + /// Do not swallow an unmatched ')', ']', or '}'. + StopAtUnbalanced = 1 << 3 }; friend constexpr SkipUntilFlags operator|(SkipUntilFlags L, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d701cbaa43bdd..0e67f83f76b3b 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4581,7 +4581,10 @@ bool Parser::ParseCXX11AttributeArgs( ScopeName, AttrName, getTargetInfo(), getLangOpts())) { // Eat the left paren, then skip to the ending right paren. ConsumeParen(); - SkipUntil(tok::r_paren); + if (!SkipUntil(tok::r_paren, StopAtUnbalanced)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + } return false; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 84059a41238cc..c67bb8503735c 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -394,16 +394,22 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { case tok::r_paren: if (ParenCount && !isFirstTokenSkipped) return false; // Matches something. + if (HasFlagsSet(Flags, StopAtUnbalanced)) + return false; ConsumeParen(); break; case tok::r_square: if (BracketCount && !isFirstTokenSkipped) return false; // Matches something. + if (HasFlagsSet(Flags, StopAtUnbalanced)) + return false; ConsumeBracket(); break; case tok::r_brace: if (BraceCount && !isFirstTokenSkipped) return false; // Matches something. + if (HasFlagsSet(Flags, StopAtUnbalanced)) + return false; ConsumeBrace(); break; diff --git a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp new file mode 100644 index 0000000000000..ba132bca19c72 --- /dev/null +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c23 %s + +[[X1(])]]; // expected-error {{expected ')'}} expected-warning {{unknown attribute 'X1' ignored}} +[[X1(})]]; // expected-error {{expected ')'}} expected-warning {{unknown attribute 'X1' ignored}} +[[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} +[[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} \ No newline at end of file >From 6756cc54b4e3e0ef9bc643d3847c9b89fb52fe1b Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Sun, 6 Sep 2026 11:25:33 +0000 Subject: [PATCH 2/7] Retrigger CI >From f79dfafc594a56216daa053fbc65538a2c5682ee Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Thu, 10 Sep 2026 09:24:15 +0000 Subject: [PATCH 3/7] [Clang][Parser] Diagnose unbalanced attr args as a pedantic warning --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++ clang/lib/Parse/ParseDeclCXX.cpp | 2 +- clang/test/Parser/cxx11-unbalanced-attr-args.cpp | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index a06d3c899453c..ba8d0636a17c1 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -826,6 +826,8 @@ def err_using_attribute_ns_conflict : Error< "attribute with scope specifier cannot follow default scope specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_keyword_not_allowed : Error<"%0 cannot appear here">; +def ext_unbalanced_attribute_args : ExtWarn< + "attribute argument list is not a balanced token sequence">, InGroup<Pedantic>; def ext_cxx11_attr_placement : ExtWarn< "ISO C++ does not allow %select{an attribute list|%0}1 to appear here">, InGroup<DiagGroup<"cxx-attribute-extension">>; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 0e67f83f76b3b..2b8b052721b8d 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4582,7 +4582,7 @@ bool Parser::ParseCXX11AttributeArgs( // Eat the left paren, then skip to the ending right paren. ConsumeParen(); if (!SkipUntil(tok::r_paren, StopAtUnbalanced)) { - Diag(Tok, diag::err_expected) << tok::r_paren; + Diag(Tok, diag::ext_unbalanced_attribute_args); SkipUntil(tok::r_paren, StopAtSemi); } return false; diff --git a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp index ba132bca19c72..a24e1cf46cdde 100644 --- a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c23 %s - -[[X1(])]]; // expected-error {{expected ')'}} expected-warning {{unknown attribute 'X1' ignored}} -[[X1(})]]; // expected-error {{expected ')'}} expected-warning {{unknown attribute 'X1' ignored}} -[[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} -[[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} \ No newline at end of file +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c23 %s + +[[X1(])]]; // expected-warning {{attribute argument list is not a balanced token sequence}} expected-warning {{unknown attribute 'X1' ignored}} +[[X1(})]]; // expected-warning {{attribute argument list is not a balanced token sequence}} expected-warning {{unknown attribute 'X1' ignored}} +[[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} +[[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} >From bc93de7d3c8b2312099a42669129407bcccc66a5 Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Thu, 10 Sep 2026 12:08:49 +0000 Subject: [PATCH 4/7] [Clang][Parser] Put unbalanced attr-args warning in its own group --- clang/include/clang/Basic/DiagnosticParseKinds.td | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index ba8d0636a17c1..9b631b0056969 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -827,7 +827,8 @@ def err_using_attribute_ns_conflict : Error< def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_keyword_not_allowed : Error<"%0 cannot appear here">; def ext_unbalanced_attribute_args : ExtWarn< - "attribute argument list is not a balanced token sequence">, InGroup<Pedantic>; + "attribute argument list is not a balanced token sequence">, + InGroup<DiagGroup<"unbalanced-attribute-args">>; def ext_cxx11_attr_placement : ExtWarn< "ISO C++ does not allow %select{an attribute list|%0}1 to appear here">, InGroup<DiagGroup<"cxx-attribute-extension">>; >From da966504a81e948fb4c395e1e01d892409f6ec92 Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Wed, 30 Sep 2026 06:18:21 +0000 Subject: [PATCH 5/7] clang: make unbalanced attribute args pedantic warning --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +- clang/test/Parser/cxx11-unbalanced-attr-args.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9b631b0056969..48c03e6b16468 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -826,7 +826,7 @@ def err_using_attribute_ns_conflict : Error< "attribute with scope specifier cannot follow default scope specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_keyword_not_allowed : Error<"%0 cannot appear here">; -def ext_unbalanced_attribute_args : ExtWarn< +def ext_unbalanced_attribute_args : Extension< "attribute argument list is not a balanced token sequence">, InGroup<DiagGroup<"unbalanced-attribute-args">>; def ext_cxx11_attr_placement : ExtWarn< diff --git a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp index a24e1cf46cdde..ec74c482fd6b2 100644 --- a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -1,7 +1,11 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,pedantic -std=c++11 -pedantic %s // RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c23 %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,pedantic -x c -std=c23 -pedantic %s -[[X1(])]]; // expected-warning {{attribute argument list is not a balanced token sequence}} expected-warning {{unknown attribute 'X1' ignored}} -[[X1(})]]; // expected-warning {{attribute argument list is not a balanced token sequence}} expected-warning {{unknown attribute 'X1' ignored}} -[[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} -[[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} +void test() { + [[X1(])]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} + [[X1(})]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} + [[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} +} >From e04271fc2d8b8e7d1d0bda2e9214957e8a9fb519 Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Wed, 7 Oct 2026 11:32:22 +0000 Subject: [PATCH 6/7] [Clang][Parser] Add tests for unbalanced attribute arguments --- .../Parser/cxx11-unbalanced-attr-args.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp index ec74c482fd6b2..09416a92b8382 100644 --- a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -9,3 +9,23 @@ void test() { [[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} [[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} } + +void test1() { + [[X1())]]; // expected-error {{expected ','}} expected-warning {{unknown attribute 'X1' ignored}} +} + +void test2() { + [[X1([)]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} // expected-error {{expected statement}} + +void test3() { + [[X1({)]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} // expected-error {{expected statement}} + +void test4() { + [[X1(()]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} // expected-error {{expected statement}} + +void test5() { + [[X1([[[[[]]]])]]; // expected-warning {{unknown attribute 'X1' ignored}} +} >From 3fd796ba1737d6555765a90373e29065bfe8ac1b Mon Sep 17 00:00:00 2001 From: neharaj <[email protected]> Date: Wed, 21 Oct 2026 12:54:12 +0000 Subject: [PATCH 7/7] [Clang][Parser] Count nested tokens when skipping unknown attribute arguments --- clang/lib/Parse/ParseDeclCXX.cpp | 10 ++- clang/lib/Parse/Parser.cpp | 79 +++++++++++++++++-- .../Parser/cxx11-unbalanced-attr-args.cpp | 23 ++++-- 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 2b8b052721b8d..a32e5e28b06bc 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4580,11 +4580,15 @@ bool Parser::ParseCXX11AttributeArgs( : AttributeCommonInfo::Syntax::AS_C23, ScopeName, AttrName, getTargetInfo(), getLangOpts())) { // Eat the left paren, then skip to the ending right paren. + unsigned SavedParenCount = ParenCount; + unsigned SavedBracketCount = BracketCount; + unsigned SavedBraceCount = BraceCount; ConsumeParen(); - if (!SkipUntil(tok::r_paren, StopAtUnbalanced)) { + if (!SkipUntil(tok::r_paren, StopAtUnbalanced)) Diag(Tok, diag::ext_unbalanced_attribute_args); - SkipUntil(tok::r_paren, StopAtSemi); - } + ParenCount = SavedParenCount; + BracketCount = SavedBracketCount; + BraceCount = SavedBraceCount; return false; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index c67bb8503735c..123ba234e0847 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -292,6 +292,79 @@ static bool HasFlagsSet(Parser::SkipUntilFlags L, Parser::SkipUntilFlags R) { } bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { + // Unknown-attribute arguments only. The loop below is unchanged. +if (HasFlagsSet(Flags, StopAtUnbalanced)) { + bool Unbalanced = false; + unsigned ParenDepth = 0, BracketDepth = 0, BraceDepth = 0; + while (true) { + if (Tok.is(tok::eof)) + return false; + + if (ParenDepth == 0 && BracketDepth == 0 && BraceDepth == 0) { + for (unsigned I = 0, E = Toks.size(); I != E; ++I) { + if (Tok.is(Toks[I])) { + if (!HasFlagsSet(Flags, StopBeforeMatch)) + ConsumeAnyToken(); + return !Unbalanced; + } + } + } + + // ']]' closes the attribute. Do not treat it as a bracket we opened. + if (Tok.is(tok::r_square) && NextToken().is(tok::r_square) && + BracketDepth <= 1) + return false; + + switch (Tok.getKind()) { + case tok::l_paren: + ++ParenDepth; + ConsumeParen(); + break; + case tok::l_square: + ++BracketDepth; + ConsumeBracket(); + break; + case tok::l_brace: + ++BraceDepth; + ConsumeBrace(); + break; + case tok::r_paren: + if (ParenDepth == 0) { + Unbalanced = true; + ConsumeParen(); + break; + } + --ParenDepth; + ConsumeParen(); + break; + case tok::r_square: + if (BracketDepth == 0) { + Unbalanced = true; + ConsumeBracket(); + break; + } + --BracketDepth; + ConsumeBracket(); + break; + case tok::r_brace: + if (BraceDepth == 0) { + Unbalanced = true; + ConsumeBrace(); + break; + } + --BraceDepth; + ConsumeBrace(); + break; + case tok::code_completion: + if (!HasFlagsSet(Flags, StopAtCodeCompletion)) + handleUnexpectedCodeCompletionToken(); + return false; + default: + ConsumeAnyToken(); + break; + } + } +} // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; @@ -394,22 +467,16 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { case tok::r_paren: if (ParenCount && !isFirstTokenSkipped) return false; // Matches something. - if (HasFlagsSet(Flags, StopAtUnbalanced)) - return false; ConsumeParen(); break; case tok::r_square: if (BracketCount && !isFirstTokenSkipped) return false; // Matches something. - if (HasFlagsSet(Flags, StopAtUnbalanced)) - return false; ConsumeBracket(); break; case tok::r_brace: if (BraceCount && !isFirstTokenSkipped) return false; // Matches something. - if (HasFlagsSet(Flags, StopAtUnbalanced)) - return false; ConsumeBrace(); break; diff --git a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp index 09416a92b8382..e4024cc88ccc4 100644 --- a/clang/test/Parser/cxx11-unbalanced-attr-args.cpp +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -8,6 +8,10 @@ void test() { [[X1(})]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} [[X1]]; // expected-warning {{unknown attribute 'X1' ignored}} [[X1()]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1([])]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1({})]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1(())]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1(a;b)]]; // expected-warning {{unknown attribute 'X1' ignored}} } void test1() { @@ -15,17 +19,22 @@ void test1() { } void test2() { - [[X1([)]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} -} // expected-error {{expected statement}} + [[X1([)]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} void test3() { - [[X1({)]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} -} // expected-error {{expected statement}} + [[X1({)]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} void test4() { - [[X1(()]]; // expected-error {{expected ']'}} pedantic-warning {{attribute argument list is not a balanced token sequence}} -} // expected-error {{expected statement}} + [[X1(()]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} void test5() { - [[X1([[[[[]]]])]]; // expected-warning {{unknown attribute 'X1' ignored}} + [[X1([[[[[]]]])]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} } + +void test6() { + [[X1(]a)]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} + [[X1(];)]]; // expected-warning {{unknown attribute 'X1' ignored}} pedantic-warning {{attribute argument list is not a balanced token sequence}} +} \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
