From 65429f73a83e95601fef26d4b6225c58c8bd441b Mon Sep 17 00:00:00 2001
From: Richard Smith <richard-llvm@metafoo.co.uk>
Date: Sun, 18 Dec 2016 22:01:46 +0000
Subject: [PATCH] Fix name hiding and redeclaration checking for dependent
 local using-declarations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290072 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaDeclCXX.cpp                      | 40 +++++++++++--------
 lib/Sema/SemaLookup.cpp                       |  9 +++--
 .../namespace.udecl/p8-cxx0x.cpp              | 39 +++++++++---------
 3 files changed, 49 insertions(+), 39 deletions(-)

diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 4742995926f..ac643af1490 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -9247,6 +9247,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
                                        const CXXScopeSpec &SS,
                                        SourceLocation NameLoc,
                                        const LookupResult &Prev) {
+  NestedNameSpecifier *Qual = SS.getScopeRep();
+
   // C++03 [namespace.udecl]p8:
   // C++0x [namespace.udecl]p10:
   //   A using-declaration is a declaration and can therefore be used
@@ -9254,10 +9256,28 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
   //   allowed.
   //
   // That's in non-member contexts.
-  if (!CurContext->getRedeclContext()->isRecord())
+  if (!CurContext->getRedeclContext()->isRecord()) {
+    // A dependent qualifier outside a class can only ever resolve to an
+    // enumeration type. Therefore it conflicts with any other non-type
+    // declaration in the same scope.
+    // FIXME: How should we check for dependent type-type conflicts at block
+    // scope?
+    if (Qual->isDependent() && !HasTypenameKeyword) {
+      for (auto *D : Prev) {
+        if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D)) {
+          bool OldCouldBeEnumerator =
+              isa<UnresolvedUsingValueDecl>(D) || isa<EnumConstantDecl>(D);
+          Diag(NameLoc,
+               OldCouldBeEnumerator ? diag::err_redefinition
+                                    : diag::err_redefinition_different_kind)
+              << Prev.getLookupName();
+          Diag(D->getLocation(), diag::note_previous_definition);
+          return true;
+        }
+      }
+    }
     return false;
-
-  NestedNameSpecifier *Qual = SS.getScopeRep();
+  }
 
   for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
     NamedDecl *D = *I;
@@ -9275,19 +9295,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
                  = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
       DTypename = true;
       DQual = UD->getQualifier();
-    } else if (!isa<TypeDecl>(D) && Qual->isDependent() &&
-               !HasTypenameKeyword) {
-      // A dependent qualifier outside a class can only ever resolve to an
-      // enumeration type. Therefore it conflicts with any other non-type
-      // declaration in the same scope.
-      // FIXME: How should we check for dependent type-type conflicts at block
-      // scope?
-      Diag(NameLoc, diag::err_redefinition_different_kind)
-          << Prev.getLookupName();
-      Diag(D->getLocation(), diag::note_previous_definition);
-      return true;
-    }
-    else continue;
+    } else continue;
 
     // using decls differ if one says 'typename' and the other doesn't.
     // FIXME: non-dependent using decls?
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1fc6d4fd515..38a7b8c127c 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -450,15 +450,18 @@ static bool canHideTag(NamedDecl *D) {
   //   Given a set of declarations in a single declarative region [...]
   //   exactly one declaration shall declare a class name or enumeration name
   //   that is not a typedef name and the other declarations shall all refer to
-  //   the same variable or enumerator, or all refer to functions and function
-  //   templates; in this case the class name or enumeration name is hidden.
+  //   the same variable, non-static data member, or enumerator, or all refer
+  //   to functions and function templates; in this case the class name or
+  //   enumeration name is hidden.
   // C++ [basic.scope.hiding]p2:
   //   A class name or enumeration name can be hidden by the name of a
   //   variable, data member, function, or enumerator declared in the same
   //   scope.
+  // An UnresolvedUsingValueDecl always instantiates to one of these.
   D = D->getUnderlyingDecl();
   return isa<VarDecl>(D) || isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D) ||
-         isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D);
+         isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D) ||
+         isa<UnresolvedUsingValueDecl>(D);
 }
 
 /// Resolves the result kind of this lookup.
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
index 8f6638e6943..0ea4eeb1e9b 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
@@ -87,12 +87,12 @@ namespace PR21933 {
     extern int a(); // expected-error {{different kind of symbol}}
     a();
 
-    extern int b();
-    using T::b;
+    extern int b(); // expected-note {{previous}}
+    using T::b; // expected-error {{different kind of symbol}}
     b();
 
-    using T::c;
-    using U::c;
+    using T::c; // expected-note {{previous}}
+    using U::c; // expected-error-re {{redefinition of 'c'{{$}}}}
     c();
   }
 
@@ -101,29 +101,28 @@ namespace PR21933 {
     typedef struct {} Xt; // expected-error {{different kind of symbol}}
     (void)Xt;
 
-    using T::Xs; // expected-note {{candidate}}
-    struct Xs {}; // expected-note {{candidate}}
-    // FIXME: This is wrong, the using declaration hides the type.
-    Xs xs; // expected-error {{ambiguous}}
+    using T::Xs; // expected-note {{hidden by}}
+    struct Xs {};
+    (void)Xs;
+    Xs xs; // expected-error {{must use 'struct'}}
 
-    using T::Xe; // expected-note {{candidate}}
-    enum Xe {}; // expected-note {{candidate}}
-    // FIXME: This is wrong, the using declaration hides the type.
-    Xe xe; // expected-error {{ambiguous}}
+    using T::Xe; // expected-note {{hidden by}}
+    enum Xe {};
+    (void)Xe;
+    Xe xe; // expected-error {{must use 'enum'}}
 
     typedef struct {} Yt; // expected-note {{candidate}}
     using T::Yt; // eypected-error {{different kind of symbol}} expected-note {{candidate}}
     Yt yt; // expected-error {{ambiguous}}
 
-    struct Ys {}; // expected-note {{candidate}}
-    using T::Ys; // expected-note {{candidate}}
-    // FIXME: This is wrong, the using declaration hides the type.
-    Ys ys; // expected-error {{ambiguous}}
+    struct Ys {};
+    using T::Ys; // expected-note {{hidden by}}
+    (void)Ys;
+    Ys ys; // expected-error {{must use 'struct'}}
 
-    enum Ye {}; // expected-note {{candidate}}
-    using T::Ye; // expected-note {{candidate}}
-    // FIXME: This is wrong, the using declaration hides the type.
-    Ye ye; // expected-error {{ambiguous}}
+    enum Ye {};
+    using T::Ye; // expected-note {{hidden by}}
+    Ye ye; // expected-error {{must use 'enum'}}
   }
 
   template<typename T> void type() {
-- 
GitLab