forked from OSchip/llvm-project
Improve diagnostics for malformed constructor declarations (where lookup for
the type of the first parameter fails, and it is the only, unnamed, parameter). llvm-svn: 202759
This commit is contained in:
parent
38dcdb744f
commit
446161b9ac
|
@ -1797,7 +1797,7 @@ private:
|
|||
/// \brief Starting with a scope specifier, identifier, or
|
||||
/// template-id that refers to the current class, determine whether
|
||||
/// this is a constructor declarator.
|
||||
bool isConstructorDeclarator();
|
||||
bool isConstructorDeclarator(bool Unqualified);
|
||||
|
||||
/// \brief Specifies the context in which type-id/expression
|
||||
/// disambiguation will occur.
|
||||
|
|
|
@ -2592,7 +2592,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
|
||||
TemplateId->Name &&
|
||||
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
|
||||
if (isConstructorDeclarator()) {
|
||||
if (isConstructorDeclarator(/*Unqualified*/false)) {
|
||||
// The user meant this to be an out-of-line constructor
|
||||
// definition, but template arguments are not allowed
|
||||
// there. Just allow this as a constructor; we'll
|
||||
|
@ -2642,7 +2642,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
|
||||
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
|
||||
&SS)) {
|
||||
if (isConstructorDeclarator())
|
||||
if (isConstructorDeclarator(/*Unqualified*/false))
|
||||
goto DoneWithDeclSpec;
|
||||
|
||||
// As noted in C++ [class.qual]p2 (cited above), when the name
|
||||
|
@ -2789,7 +2789,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// check whether this is a constructor declaration.
|
||||
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
|
||||
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
|
||||
isConstructorDeclarator())
|
||||
isConstructorDeclarator(/*Unqualified*/true))
|
||||
goto DoneWithDeclSpec;
|
||||
|
||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
||||
|
@ -2825,7 +2825,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// constructor declaration.
|
||||
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
|
||||
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
|
||||
isConstructorDeclarator())
|
||||
isConstructorDeclarator(TemplateId->SS.isEmpty()))
|
||||
goto DoneWithDeclSpec;
|
||||
|
||||
// Turn the template-id annotation token into a type annotation
|
||||
|
@ -4250,7 +4250,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Parser::isConstructorDeclarator() {
|
||||
bool Parser::isConstructorDeclarator(bool IsUnqualified) {
|
||||
TentativeParsingAction TPA(*this);
|
||||
|
||||
// Parse the C++ scope specifier.
|
||||
|
@ -4332,12 +4332,35 @@ bool Parser::isConstructorDeclarator() {
|
|||
case tok::coloncolon:
|
||||
// C(X :: Y);
|
||||
// C(X :: *p);
|
||||
case tok::r_paren:
|
||||
// C(X )
|
||||
// Assume this isn't a constructor, rather than assuming it's a
|
||||
// constructor with an unnamed parameter of an ill-formed type.
|
||||
break;
|
||||
|
||||
case tok::r_paren:
|
||||
// C(X )
|
||||
if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) {
|
||||
// Assume these were meant to be constructors:
|
||||
// C(X) : (the name of a bit-field cannot be parenthesized).
|
||||
// C(X) try (this is otherwise ill-formed).
|
||||
IsConstructor = true;
|
||||
}
|
||||
if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) {
|
||||
// If we have a constructor name within the class definition,
|
||||
// assume these were meant to be constructors:
|
||||
// C(X) {
|
||||
// C(X) ;
|
||||
// ... because otherwise we would be declaring a non-static data
|
||||
// member that is ill-formed because it's of the same type as its
|
||||
// surrounding class.
|
||||
//
|
||||
// FIXME: We can actually do this whether or not the name is qualified,
|
||||
// because if it is qualified in this context it must be being used as
|
||||
// a constructor name. However, we do not implement that rule correctly
|
||||
// currently, so we're somewhat conservative here.
|
||||
IsConstructor = IsUnqualified;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
IsConstructor = true;
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -fcxx-exceptions %s
|
||||
class C;
|
||||
class C {
|
||||
public:
|
||||
|
@ -123,6 +123,22 @@ class pr16989 {
|
|||
};
|
||||
};
|
||||
|
||||
namespace CtorErrors {
|
||||
struct A {
|
||||
A(NonExistent); // expected-error {{unknown type name 'NonExistent'}}
|
||||
};
|
||||
struct B {
|
||||
B(NonExistent) : n(0) {} // expected-error {{unknown type name 'NonExistent'}}
|
||||
int n;
|
||||
};
|
||||
struct C {
|
||||
C(NonExistent) try {} catch (...) {} // expected-error {{unknown type name 'NonExistent'}}
|
||||
};
|
||||
struct D {
|
||||
D(NonExistent) {} // expected-error {{unknown type name 'NonExistent'}}
|
||||
};
|
||||
}
|
||||
|
||||
// PR11109 must appear at the end of the source file
|
||||
class pr11109r3 { // expected-note{{to match this '{'}}
|
||||
public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}
|
||||
|
|
Loading…
Reference in New Issue