[modules] Retain multiple using-directives in the same scope even if they name the...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 30 Oct 2017 22:38:20 +0000 (22:38 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 30 Oct 2017 22:38:20 +0000 (22:38 +0000)
They might have different visibility, and thus discarding all but one of them
can result in rejecting valid code. Also fix name lookup to cope with multiple
using-directives being found that denote the same namespace, where some are not
visible -- don't cache an "already visited" state for a using-directive that we
didn't visit because it was hidden.

llvm-svn: 316965

clang/lib/AST/Decl.cpp
clang/lib/Sema/SemaLookup.cpp
clang/test/Modules/using-directive-redecl.cpp [new file with mode: 0644]

index f27df1d..32a4907 100644 (file)
@@ -1597,14 +1597,6 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
                         cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
   }
 
-  // UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
-  // They can be replaced if they nominate the same namespace.
-  // FIXME: Is this true even if they have different module visibility?
-  if (auto *UD = dyn_cast<UsingDirectiveDecl>(this))
-    return UD->getNominatedNamespace()->getOriginalNamespace() ==
-           cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace()
-               ->getOriginalNamespace();
-
   if (isRedeclarable(getKind())) {
     if (getCanonicalDecl() != OldD->getCanonicalDecl())
       return false;
index 73aceaa..d3f91a4 100644 (file)
@@ -155,7 +155,7 @@ namespace {
       while (true) {
         for (auto UD : DC->using_directives()) {
           DeclContext *NS = UD->getNominatedNamespace();
-          if (visited.insert(NS).second && SemaRef.isVisible(UD)) {
+          if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
             addUsingDirective(UD, EffectiveDC);
             queue.push_back(NS);
           }
@@ -1883,7 +1883,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
   // with its using-children.
   for (auto *I : StartDC->using_directives()) {
     NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
-    if (Visited.insert(ND).second && S.isVisible(I))
+    if (S.isVisible(I) && Visited.insert(ND).second)
       Queue.push_back(ND);
   }
 
@@ -1931,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
 
     for (auto I : ND->using_directives()) {
       NamespaceDecl *Nom = I->getNominatedNamespace();
-      if (Visited.insert(Nom).second && S.isVisible(I))
+      if (S.isVisible(I) && Visited.insert(Nom).second)
         Queue.push_back(Nom);
     }
   }
diff --git a/clang/test/Modules/using-directive-redecl.cpp b/clang/test/Modules/using-directive-redecl.cpp
new file mode 100644 (file)
index 0000000..94772f3
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -verify %s
+// expected-no-diagnostics
+#pragma clang module build M
+module M { module TDFNodes {} module TDFInterface {} }
+#pragma clang module contents
+  // TDFNodes
+  #pragma clang module begin M.TDFNodes
+  namespace Detail {
+     namespace TDF {
+        class TLoopManager {};
+     }
+  }
+  namespace Internal {
+     namespace TDF {
+        using namespace Detail::TDF;
+     }
+  }
+  #pragma clang module end
+
+  // TDFInterface
+  #pragma clang module begin M.TDFInterface
+    #pragma clang module import M.TDFNodes
+      namespace Internal {
+        namespace TDF {
+          using namespace Detail::TDF;
+        }
+      }
+  #pragma clang module end
+
+#pragma clang module endbuild
+
+#pragma clang module import M.TDFNodes
+namespace Internal {
+  namespace TDF {
+    TLoopManager * use;
+  }
+}