diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ae91153e34e3a..c69cb71e9988e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3078,7 +3078,7 @@ class Parser : public CodeCompletionHandler { /// attribute-specifier-seq[opt] attribute-specifier /// \endverbatim void ParseCXX11Attributes(ParsedAttributes &attrs); - + bool SkipBalancedAttributeArgs(tok::TokenKind Closer); /// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause. /// Parses a C++11 (or C23)-style attribute argument list. Returns true /// if this results in adding an attribute to the ParsedAttributes list. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d701cbaa43bdd..00bf283cffd7e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -4534,7 +4534,43 @@ bool Parser::ParseCXXAssumeAttributeArg( return false; } +bool Parser::SkipBalancedAttributeArgs(tok::TokenKind Closer) { + while (true) { + if (Tok.is(Closer)) + return true; + if (Tok.is(tok::eof)) + return false; + switch (Tok.getKind()) { + case tok::l_paren: + ConsumeParen(); + if (!SkipBalancedAttributeArgs(tok::r_paren) || + ExpectAndConsume(tok::r_paren)) + return false; + break; + case tok::l_square: + ConsumeBracket(); + if (!SkipBalancedAttributeArgs(tok::r_square) || + ExpectAndConsume(tok::r_square)) + return false; + break; + case tok::l_brace: + ConsumeBrace(); + if (!SkipBalancedAttributeArgs(tok::r_brace) || + ExpectAndConsume(tok::r_brace)) + return false; + break; + case tok::r_paren: + case tok::r_square: + case tok::r_brace: + Diag(Tok, diag::err_expected) << Closer; + return false; + default: + ConsumeAnyToken(); + break; + } + } +} bool Parser::ParseCXX11AttributeArgs( IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, @@ -4581,7 +4617,9 @@ bool Parser::ParseCXX11AttributeArgs( ScopeName, AttrName, getTargetInfo(), getLangOpts())) { // Eat the left paren, then skip to the ending right paren. ConsumeParen(); - SkipUntil(tok::r_paren); + if (!SkipBalancedAttributeArgs(tok::r_paren) || + ExpectAndConsume(tok::r_paren)) + 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 new file mode 100644 index 0000000000000..ca5cbb76eba7d --- /dev/null +++ b/clang/test/Parser/cxx11-unbalanced-attr-args.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %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}}