Fix constructor declarator detection for the case when the name is followed by

an attribute-specifier-seq. (Also fixes the same problem for deduction-guides.)

llvm-svn: 294396
This commit is contained in:
Richard Smith 2017-02-08 01:16:55 +00:00
parent f283fdcd50
commit 8f8697f3e1
3 changed files with 20 additions and 8 deletions

View File

@ -4675,6 +4675,10 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
return false; return false;
} }
// There may be attributes here, appertaining to the constructor name or type
// we just stepped past.
SkipCXX11Attributes();
// Current class name must be followed by a left parenthesis. // Current class name must be followed by a left parenthesis.
if (Tok.isNot(tok::l_paren)) { if (Tok.isNot(tok::l_paren)) {
TPA.Revert(); TPA.Revert();
@ -4742,18 +4746,24 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
case tok::r_paren: case tok::r_paren:
// C(X ) // C(X )
// Skip past the right-paren and any following attributes to get to
// the function body or trailing-return-type.
ConsumeParen();
SkipCXX11Attributes();
if (DeductionGuide) { if (DeductionGuide) {
// C(X) -> ... is a deduction guide. // C(X) -> ... is a deduction guide.
IsConstructor = NextToken().is(tok::arrow); IsConstructor = Tok.is(tok::arrow);
break; break;
} }
if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) { if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
// Assume these were meant to be constructors: // Assume these were meant to be constructors:
// C(X) : (the name of a bit-field cannot be parenthesized). // C(X) : (the name of a bit-field cannot be parenthesized).
// C(X) try (this is otherwise ill-formed). // C(X) try (this is otherwise ill-formed).
IsConstructor = true; IsConstructor = true;
} }
if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) { if (Tok.is(tok::semi) || Tok.is(tok::l_brace)) {
// If we have a constructor name within the class definition, // If we have a constructor name within the class definition,
// assume these were meant to be constructors: // assume these were meant to be constructors:
// C(X) { // C(X) {

View File

@ -31,7 +31,7 @@ A(int(&)[5])[3] -> A<int>;
// (Pending DR) attributes and parens around the declarator-id are OK. // (Pending DR) attributes and parens around the declarator-id are OK.
[[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]]; [[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]];
A [[]] (int(&)[7]) -> A<int>; // FIXME: expected-error 2{{expected}} expected-note {{to match}} A [[]] (int(&)[7]) -> A<int>;
(A)(int(&)[8]) -> A<int>; (A)(int(&)[8]) -> A<int>;
// ... but the trailing-return-type is part of the function-declarator as normal // ... but the trailing-return-type is part of the function-declarator as normal

View File

@ -99,11 +99,13 @@ void fn_with_structs() {
} }
[[]]; [[]];
struct ctordtor { struct ctordtor {
[[]] ctordtor(); [[]] ctordtor [[]] () [[]];
[[]] ~ctordtor(); ctordtor (C) [[]];
[[]] ~ctordtor [[]] () [[]];
}; };
[[]] ctordtor::ctordtor() {} [[]] ctordtor::ctordtor [[]] () [[]] {}
[[]] ctordtor::~ctordtor() {} [[]] ctordtor::ctordtor (C) [[]] try {} catch (...) {}
[[]] ctordtor::~ctordtor [[]] () [[]] {}
extern "C++" [[]] int extern_attr; extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr (); template <typename T> [[]] void template_attr ();
[[]] [[]] int [[]] [[]] multi_attr [[]] [[]]; [[]] [[]] int [[]] [[]] multi_attr [[]] [[]];