r202759 - Improve diagnostics for malformed constructor declarations (where lookup for
Richard Smith
richard-llvm at metafoo.co.uk
Mon Mar 3 13:12:53 PST 2014
Author: rsmith
Date: Mon Mar 3 15:12:53 2014
New Revision: 202759
URL: http://llvm.org/viewvc/llvm-project?rev=202759&view=rev
Log:
Improve diagnostics for malformed constructor declarations (where lookup for
the type of the first parameter fails, and it is the only, unnamed, parameter).
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/test/Parser/cxx-class.cpp
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=202759&r1=202758&r2=202759&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Mar 3 15:12:53 2014
@@ -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.
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=202759&r1=202758&r2=202759&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 3 15:12:53 2014
@@ -2592,7 +2592,7 @@ void Parser::ParseDeclarationSpecifiers(
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(
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(
// 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(
// 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
}
}
-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;
Modified: cfe/trunk/test/Parser/cxx-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-class.cpp?rev=202759&r1=202758&r2=202759&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx-class.cpp (original)
+++ cfe/trunk/test/Parser/cxx-class.cpp Mon Mar 3 15:12:53 2014
@@ -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}}
More information about the cfe-commits
mailing list