forked from OSchip/llvm-project
Fix TryParsePtrOperatorSeq.
The syntax rules for ptr-operator allow attributes after *, &, &&, therefore we should be able to parse the following: void fn() { void (*[[attr]] x)() = &fn; void (&[[attr]] y)() = fn; void (&&[[attr]] z)() = fn; } However the current logic in TryParsePtrOperatorSeq does not consider the presence of attributes leading to unexpected parsing errors. Moreover we should also consider _Atomic a possible qualifier that can appear after the sequence of attribute specifiers.
This commit is contained in:
parent
12fed51c08
commit
bd5b22070b
|
@ -2442,6 +2442,10 @@ private:
|
|||
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
|
||||
|
|
|
@ -186,21 +186,8 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
|
|||
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 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
|
|||
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 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
|
|||
(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;
|
||||
|
|
|
@ -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 @@ struct X {
|
|||
};
|
||||
|
||||
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];
|
||||
}
|
||||
|
|
|
@ -38,4 +38,7 @@ void arr() {
|
|||
// 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;
|
||||
}
|
||||
|
|
|
@ -22,3 +22,15 @@ namespace PR17666 {
|
|||
}
|
||||
|
||||
__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];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue