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

Reply via email to