diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2442,6 +2442,10 @@ TPResult TryParseBracketDeclarator(); TPResult TryConsumeDeclarationSpecifier(); + /// Try to skip a possibly empty sequence of 'attribute-specifier's without + /// full validation of the syntactic structure of attributes. + bool TrySkipAttributes(); + public: TypeResult ParseTypeName(SourceRange *Range = nullptr, DeclaratorContext Context diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -186,21 +186,8 @@ ConsumeToken(); // Skip attributes. - while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec, - tok::kw_alignas)) { - if (Tok.is(tok::l_square)) { - ConsumeBracket(); - if (!SkipUntil(tok::r_square)) - return TPResult::Error; - } else { - ConsumeToken(); - if (Tok.isNot(tok::l_paren)) - return TPResult::Error; - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error; - } - } + if (!TrySkipAttributes()) + return TPResult::Error; if (TryAnnotateOptionalCXXScopeToken()) return TPResult::Error; @@ -781,6 +768,32 @@ return CAK_NotAttributeSpecifier; } +bool Parser::TrySkipAttributes() { + while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec, + tok::kw_alignas)) { + if (Tok.is(tok::l_square)) { + ConsumeBracket(); + if (Tok.isNot(tok::l_square)) + return false; + ConsumeBracket(); + if (!SkipUntil(tok::r_square) || Tok.isNot(tok::r_square)) + return false; + // Note that explicitly checking for `[[` and `]]` allows to fail as + // expected in the case of the Objective-C message send syntax. + ConsumeBracket(); + } else { + ConsumeToken(); + if (Tok.isNot(tok::l_paren)) + return false; + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return false; + } + } + + return true; +} + Parser::TPResult Parser::TryParsePtrOperatorSeq() { while (true) { if (TryAnnotateOptionalCXXScopeToken(true)) @@ -790,9 +803,14 @@ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { // ptr-operator ConsumeAnyToken(); + + // Skip attributes. + if (!TrySkipAttributes()) + return TPResult::Error; + while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict, tok::kw__Nonnull, tok::kw__Nullable, - tok::kw__Null_unspecified)) + tok::kw__Null_unspecified, tok::kw__Atomic)) ConsumeToken(); } else { return TPResult::True; diff --git a/clang/test/CXX/dcl.decl/p4-0x.cpp b/clang/test/CXX/dcl.decl/p4-0x.cpp --- a/clang/test/CXX/dcl.decl/p4-0x.cpp +++ b/clang/test/CXX/dcl.decl/p4-0x.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -// expected-no-diagnostics struct X { void f() &; @@ -7,3 +6,15 @@ }; void (X::*pmf)() & = &X::f; + +void fn() { + void (*[[attr]] fn_ptr)() = &fn; // expected-warning{{unknown attribute 'attr' ignored}} + void (*[[attrA]] *[[attrB]] fn_ptr_ptr)() = &fn_ptr; // expected-warning{{unknown attribute 'attrA' ignored}} expected-warning{{unknown attribute 'attrB' ignored}} + + void (&[[attr]] fn_lref)() = fn; // expected-warning{{unknown attribute 'attr' ignored}} + void (&&[[attr]] fn_rref)() = fn; // expected-warning{{unknown attribute 'attr' ignored}} + + int i[5]; + int (*[[attr(i[1])]] pi); // expected-warning{{unknown attribute 'attr' ignored}} + pi = &i[0]; +} diff --git a/clang/test/Parser/cxx-ambig-decl-expr.cpp b/clang/test/Parser/cxx-ambig-decl-expr.cpp --- a/clang/test/Parser/cxx-ambig-decl-expr.cpp +++ b/clang/test/Parser/cxx-ambig-decl-expr.cpp @@ -38,4 +38,7 @@ // These are array declarations. int(x[(1,1)]); // expected-error {{redefinition}} int(x[true ? 1,1 : 1]); // expected-error {{redefinition}} + + int (*_Atomic atomic_ptr_to_int); + *atomic_ptr_to_int = 42; } diff --git a/clang/test/Parser/cxx-attributes.cpp b/clang/test/Parser/cxx-attributes.cpp --- a/clang/test/Parser/cxx-attributes.cpp +++ b/clang/test/Parser/cxx-attributes.cpp @@ -22,3 +22,15 @@ } __attribute((typename)) int x; // expected-warning {{unknown attribute 'typename' ignored}} + +void fn() { + void (*__attribute__((attr)) fn_ptr)() = &fn; // expected-warning{{unknown attribute 'attr' ignored}} + void (*__attribute__((attrA)) *__attribute__((attrB)) fn_ptr_ptr)() = &fn_ptr; // expected-warning{{unknown attribute 'attrA' ignored}} expected-warning{{unknown attribute 'attrB' ignored}} + + void (&__attribute__((attr)) fn_lref)() = fn; // expected-warning{{unknown attribute 'attr' ignored}} + void (&&__attribute__((attr)) fn_rref)() = fn; // expected-warning{{unknown attribute 'attr' ignored}} + + int i[5]; + int (*__attribute__((attr(i[1]))) pi); // expected-warning{{unknown attribute 'attr' ignored}} + pi = &i[0]; +}