Specifically, Clang currently errors on the following code:
struct X {};
X::X x;
As the type specifier 'X::X' isn't a valid use of the injected class name,
it instead names the constructor. The code in question performs error
recovery as if this *did* name the type already, but doesn't suggest a fixit
hint to make it actually name the type. This patch adds that fixit hint.
I have a tiny reservation here that there might be cases where the
suggestion change to the code doesn't actually match the recovery's
interpretation of 'X::X', specifically a context wherhe 'X' alone wouldn't
name a class type, but 'X::X' would if it were allowed. I don't think any
such case exists, but it might, so I wanted to run it by folks first.
My code doesn't fire for templates, one obvious case where the
injected-class-name is substantially different from the nominating name in
the NNS (in that the injected-class-name is a class-name, while the NNS
would end in a template-id). And the standard clarifies that base class's
injected-class-name can still be used in these contexts so it shouldn't fire
there.
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3764a40..a1dde66 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -413,7 +413,7 @@ def err_out_of_line_template_id_names_constructor : Error<
"template name wherever a constructor can be declared">;
def err_out_of_line_type_names_constructor : Error<
"qualified reference to %0 is a constructor name rather than a "
- "type wherever a constructor can be declared">;
+ "type; omit the final class name instead">;
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index f946f79..988164d 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1459,14 +1459,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (isConstructorDeclarator())
goto DoneWithDeclSpec;
- // As noted in C++ [class.qual]p2 (cited above), when the name
- // of the class is qualified in a context where it could name
- // a constructor, its a constructor name. However, we've
- // looked at the declarator, and the user probably meant this
- // to be a type. Complain that it isn't supposed to be treated
- // as a type, then proceed to parse it as a type.
+ // As noted in C++ [class.qual]p2 (cited above), when the name of the
+ // class is qualified in a context where it could name a constructor,
+ // its a constructor name. However, we've looked at the declarator, and
+ // the user probably meant this to be a type. Complain that it isn't
+ // supposed to be treated as a type, issue a fixit hint to remove the
+ // injected class name, and then proceed to parse it as a type.
Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
- << Next.getIdentifierInfo();
+ << Next.getIdentifierInfo()
+ << FixItHint::CreateRemoval(SourceRange(SS.getEndLoc(),
+ Next.getLocation()));
}
ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
index 7ecedd5..9f8798f 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -18,7 +18,7 @@ template<typename T> X1<T>::X1<T>(int) { } // expected-error{{out-of-line constr
template<typename T> (X1<T>::X1<T>)(float) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
// Error recovery: out-of-line constructor names intended to be types
-X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type wherever a constructor can be declared}}
+X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type; omit the final class name instead}}
struct X0::X0 X0::f2() { return X0(); }
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 1028b45..0eefd6a 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -37,8 +37,8 @@ public:
X<int>::C *c1;
X<float>::C *c2;
-X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
-X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
+X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type; omit the final class name instead}}
+X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type; omit the final class name instead}}
void test_naming() {
c1 = c2; // expected-error{{assigning to 'X<int>::C *' from incompatible type 'X<float>::C *'}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits