]> granicus.if.org Git - clang/commitdiff
If a using-declaration names a class member, but appears outside a class, try
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 2 Apr 2014 21:44:35 +0000 (21:44 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 2 Apr 2014 21:44:35 +0000 (21:44 +0000)
to suggest a different syntax to get the same effect.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205467 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp

index 3704be31e7a37e8113bc68769305a5c284d83113..b138619de301520ea7c2776b1a1ee4fe3ee06fe0 100644 (file)
@@ -290,6 +290,9 @@ def note_using_decl_constructor_ellipsis : Note<
   "constructor declared with ellipsis here">;
 def err_using_decl_can_not_refer_to_class_member : Error<
   "using declaration cannot refer to class member">;
+def note_using_decl_class_member_workaround : Note<
+  "use %select{an alias declaration|a typedef declaration|a reference}0 "
+  "instead">;
 def err_using_decl_can_not_refer_to_namespace : Error<
   "using declaration cannot refer to namespace">;
 def err_using_decl_constructor : Error<
index fea0956d6fa59943b3b7f94b35b64a6e32e5e7b5..ea9344d4838b0e1d97f92c007592f8f4c29fdd46 100644 (file)
@@ -3734,6 +3734,7 @@ public:
                                    const LookupResult &Previous);
   bool CheckUsingDeclQualifier(SourceLocation UsingLoc,
                                const CXXScopeSpec &SS,
+                               const DeclarationNameInfo &NameInfo,
                                SourceLocation NameLoc);
 
   NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
index dac2490c643d8baecde469094ba54241797fcb6e..850db26e9afa02efdc682547856029bef2f1ac55 100644 (file)
@@ -7393,7 +7393,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
     return 0;
 
   // Check for bad qualifiers.
-  if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc))
+  if (CheckUsingDeclQualifier(UsingLoc, SS, NameInfo, IdentLoc))
     return 0;
 
   DeclContext *LookupContext = computeDeclContext(SS);
@@ -7619,6 +7619,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
 /// scope.  If an error is found, diagnoses it and returns true.
 bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
                                    const CXXScopeSpec &SS,
+                                   const DeclarationNameInfo &NameInfo,
                                    SourceLocation NameLoc) {
   DeclContext *NamedContext = computeDeclContext(SS);
 
@@ -7630,8 +7631,56 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
     // If we weren't able to compute a valid scope, it must be a
     // dependent class scope.
     if (!NamedContext || NamedContext->isRecord()) {
+      auto *RD = dyn_cast<CXXRecordDecl>(NamedContext);
+      if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
+        RD = 0;
+
       Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member)
         << SS.getRange();
+
+      // If we have a complete, non-dependent source type, try to suggest a
+      // way to get the same effect.
+      if (!RD)
+        return true;
+
+      // Find what this using-declaration was referring to.
+      LookupResult R(*this, NameInfo, LookupOrdinaryName);
+      R.setHideTags(false);
+      R.suppressDiagnostics();
+      LookupQualifiedName(R, RD);
+
+      if (R.getAsSingle<TypeDecl>()) {
+        if (getLangOpts().CPlusPlus11) {
+          // Convert 'using X::Y;' to 'using Y = X::Y;'.
+          Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround)
+            << 0 // alias declaration
+            << FixItHint::CreateInsertion(SS.getBeginLoc(),
+                                          NameInfo.getName().getAsString() +
+                                              " = ");
+        } else {
+          // Convert 'using X::Y;' to 'typedef X::Y Y;'.
+          SourceLocation InsertLoc =
+              PP.getLocForEndOfToken(NameInfo.getLocEnd());
+          Diag(InsertLoc, diag::note_using_decl_class_member_workaround)
+            << 1 // typedef declaration
+            << FixItHint::CreateReplacement(UsingLoc, "typedef")
+            << FixItHint::CreateInsertion(
+                   InsertLoc, " " + NameInfo.getName().getAsString());
+        }
+      } else if (R.getAsSingle<VarDecl>()) {
+        // Don't provide a fixit outside C++11 mode; we don't want to suggest
+        // repeating the type of the static data member here.
+        FixItHint FixIt;
+        if (getLangOpts().CPlusPlus11) {
+          // Convert 'using X::Y;' to 'auto &Y = X::Y;'.
+          FixIt = FixItHint::CreateReplacement(
+              UsingLoc, "auto &" + NameInfo.getName().getAsString() + " = ");
+        }
+
+        Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
+          << 2 // reference declaration
+          << FixIt;
+      }
       return true;
     }
 
index 8766c887f8b094bc11917049809d7f590f3a9246..316b574fdfaefdd82e448e05b4c2d5f331797196 100644 (file)
@@ -2169,7 +2169,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
   }
 
   if (!NewUD->isInvalidDecl() &&
-      SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS,
+      SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, NameInfo,
                                       D->getLocation()))
     NewUD->setInvalidDecl();
 
index 7d39172af2ecfa8f21e02f7df2c4b2cea207573e..4f89dcfb3f522bc40f7234299158dc1a9be9f616 100644 (file)
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++98 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX98 %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX11 %s
 // C++0x N2914.
 
 struct X {
@@ -13,3 +16,94 @@ void f() {
   using X::i; // expected-error{{using declaration cannot refer to class member}}
   using X::s; // expected-error{{using declaration cannot refer to class member}}
 }
+
+struct S {
+  static int n;
+  struct Q {};
+  enum E {};
+  typedef Q T;
+  void f();
+  static void g();
+};
+
+using S::n; // expected-error{{class member}} expected-note {{use a reference instead}}
+#if __cplusplus < 201103L
+// CXX98-NOT: fix-it:"{{.*}}":{[[@LINE-2]]
+#else
+// CXX11: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:6}:"auto &n = "
+#endif
+
+using S::Q; // expected-error{{class member}}
+#if __cplusplus < 201103L
+// expected-note@-2 {{use a typedef declaration instead}}
+// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef"
+// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" Q"
+#else
+// expected-note@-6 {{use an alias declaration instead}}
+// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"Q = "
+#endif
+
+using S::E; // expected-error{{class member}}
+#if __cplusplus < 201103L
+// expected-note@-2 {{use a typedef declaration instead}}
+// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef"
+// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" E"
+#else
+// expected-note@-6 {{use an alias declaration instead}}
+// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"E = "
+#endif
+
+using S::T; // expected-error{{class member}}
+#if __cplusplus < 201103L
+// expected-note@-2 {{use a typedef declaration instead}}
+// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef"
+// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" T"
+#else
+// expected-note@-6 {{use an alias declaration instead}}
+// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"T = "
+#endif
+
+using S::f; // expected-error{{class member}}
+using S::g; // expected-error{{class member}}
+
+void h() {
+  using S::n; // expected-error{{class member}} expected-note {{use a reference instead}}
+#if __cplusplus < 201103L
+  // CXX98-NOT: fix-it:"{{.*}}":{[[@LINE-2]]
+#else
+  // CXX11: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:8}:"auto &n = "
+#endif
+
+  using S::Q; // expected-error{{class member}}
+#if __cplusplus < 201103L
+  // expected-note@-2 {{use a typedef declaration instead}}
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef"
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" Q"
+#else
+  // expected-note@-6 {{use an alias declaration instead}}
+  // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"Q = "
+#endif
+
+  using S::E; // expected-error{{class member}}
+#if __cplusplus < 201103L
+  // expected-note@-2 {{use a typedef declaration instead}}
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef"
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" E"
+#else
+  // expected-note@-6 {{use an alias declaration instead}}
+  // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"E = "
+#endif
+
+  using S::T; // expected-error{{class member}}
+#if __cplusplus < 201103L
+  // expected-note@-2 {{use a typedef declaration instead}}
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef"
+  // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" T"
+#else
+  // expected-note@-6 {{use an alias declaration instead}}
+  // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"T = "
+#endif
+
+  using S::f; // expected-error{{class member}}
+  using S::g; // expected-error{{class member}}
+}