r256601 - Model NamespaceAliasDecls as having their nominated namespace as an underlying

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 29 15:34:33 PST 2015


Author: rsmith
Date: Tue Dec 29 17:34:32 2015
New Revision: 256601

URL: http://llvm.org/viewvc/llvm-project?rev=256601&view=rev
Log:
Model NamespaceAliasDecls as having their nominated namespace as an underlying
declaration. This fixes an issue where we would reject (due to a claimed
ambiguity) a case where lookup finds multiple NamespaceAliasDecls from
different scopes that nominate the same namespace.

The C++ standard doesn't make it clear that such a case is in fact valid (which
I'm working on fixing), but there are no relevant rules that distinguish using
declarations and namespace alias declarations here, so it makes sense to treat
them the same way.

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/namespace-alias.cpp
    cfe/trunk/test/SemaCXX/using-decl-1.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Dec 29 17:34:32 2015
@@ -319,7 +319,8 @@ public:
   NamedDecl *getUnderlyingDecl() {
     // Fast-path the common case.
     if (this->getKind() != UsingShadow &&
-        this->getKind() != ObjCCompatibleAlias)
+        this->getKind() != ObjCCompatibleAlias &&
+        this->getKind() != NamespaceAlias)
       return this;
 
     return getUnderlyingDeclImpl();

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Dec 29 17:34:32 2015
@@ -1607,6 +1607,9 @@ NamedDecl *NamedDecl::getUnderlyingDeclI
   if (auto *AD = dyn_cast<ObjCCompatibleAliasDecl>(ND))
     return AD->getClassInterface();
 
+  if (auto *AD = dyn_cast<NamespaceAliasDecl>(ND))
+    return AD->getNamespace();
+
   return ND;
 }
 

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Tue Dec 29 17:34:32 2015
@@ -291,8 +291,10 @@ bool Sema::isAcceptableNestedNameSpecifi
   if (!SD)
     return false;
 
+  SD = SD->getUnderlyingDecl();
+
   // Namespace and namespace aliases are fine.
-  if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+  if (isa<NamespaceDecl>(SD))
     return true;
 
   if (!isa<TypeDecl>(SD))
@@ -396,10 +398,7 @@ bool Sema::isNonTypeNestedNameSpecifier(
   }
   Found.suppressDiagnostics();
   
-  if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
-    return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
-  
-  return false;
+  return Found.getAsSingle<NamespaceDecl>();
 }
 
 namespace {
@@ -615,7 +614,8 @@ bool Sema::BuildCXXNestedNameSpecifier(S
     }
   }
 
-  NamedDecl *SD = Found.getAsSingle<NamedDecl>();
+  NamedDecl *SD =
+      Found.isSingleResult() ? Found.getRepresentativeDecl() : nullptr;
   bool IsExtension = false;
   bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension);
   if (!AcceptSpec && IsExtension) {
@@ -687,7 +687,8 @@ bool Sema::BuildCXXNestedNameSpecifier(S
       return false;
     }
 
-    QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+    QualType T =
+        Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl()));
     TypeLocBuilder TLB;
     if (isa<InjectedClassNameType>(T)) {
       InjectedClassNameTypeLoc InjectedTL

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Dec 29 17:34:32 2015
@@ -494,6 +494,7 @@ bool ResultBuilder::isInterestingDecl(co
                                       bool &AsNestedNameSpecifier) const {
   AsNestedNameSpecifier = false;
 
+  auto *Named = ND;
   ND = ND->getUnderlyingDecl();
 
   // Skip unnamed entities.
@@ -526,14 +527,14 @@ bool ResultBuilder::isInterestingDecl(co
         return false;
 
   if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
-      ((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
+      (isa<NamespaceDecl>(ND) &&
        Filter != &ResultBuilder::IsNamespace &&
        Filter != &ResultBuilder::IsNamespaceOrAlias &&
        Filter != nullptr))
     AsNestedNameSpecifier = true;
 
   // Filter out any unwanted results.
-  if (Filter && !(this->*Filter)(ND)) {
+  if (Filter && !(this->*Filter)(Named)) {
     // Check whether it is interesting as a nested-name-specifier.
     if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus && 
         IsNestedNameSpecifier(ND) &&
@@ -1142,14 +1143,12 @@ bool ResultBuilder::IsNamespace(const Na
 /// \brief Determines whether the given declaration is a namespace or 
 /// namespace alias.
 bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {
-  return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+  return isa<NamespaceDecl>(ND->getUnderlyingDecl());
 }
 
 /// \brief Determines whether the given declaration is a type.
 bool ResultBuilder::IsType(const NamedDecl *ND) const {
-  if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
-    ND = Using->getTargetDecl();
-  
+  ND = ND->getUnderlyingDecl();
   return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
 }
 
@@ -1157,11 +1156,9 @@ bool ResultBuilder::IsType(const NamedDe
 /// "." or "->".  Only value declarations, nested name specifiers, and
 /// using declarations thereof should show up.
 bool ResultBuilder::IsMember(const NamedDecl *ND) const {
-  if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
-    ND = Using->getTargetDecl();
-
+  ND = ND->getUnderlyingDecl();
   return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
-    isa<ObjCPropertyDecl>(ND);
+         isa<ObjCPropertyDecl>(ND);
 }
 
 static bool isObjCReceiverType(ASTContext &C, QualType T) {

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 29 17:34:32 2015
@@ -7198,7 +7198,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope
     // as if by qualified name lookup.
     LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration);
     LookupQualifiedName(R, CurContext->getRedeclContext());
-    NamedDecl *PrevDecl = R.getAsSingle<NamedDecl>();
+    NamedDecl *PrevDecl =
+        R.isSingleResult() ? R.getRepresentativeDecl() : nullptr;
     PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
 
     if (PrevNS) {
@@ -7579,9 +7580,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S
   }
   
   if (!R.empty()) {
-    NamedDecl *Named = R.getFoundDecl();
-    assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named))
-        && "expected namespace decl");
+    NamedDecl *Named = R.getRepresentativeDecl();
+    NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>();
+    assert(NS && "expected namespace decl");
 
     // The use of a nested name specifier may trigger deprecation warnings.
     DiagnoseUseOfDecl(Named, IdentLoc);
@@ -7598,7 +7599,6 @@ Decl *Sema::ActOnUsingDirective(Scope *S
 
     // Find enclosing context containing both using-directive and
     // nominated namespace.
-    NamespaceDecl *NS = getNamespaceDecl(Named);
     DeclContext *CommonAncestor = cast<DeclContext>(NS);
     while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
       CommonAncestor = CommonAncestor->getParent();
@@ -8669,7 +8669,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope
     }
   }
   assert(!R.isAmbiguous() && !R.empty());
-  NamedDecl *ND = R.getFoundDecl();
+  NamedDecl *ND = R.getRepresentativeDecl();
 
   // Check if we have a previous declaration with the same name.
   LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName,
@@ -8689,7 +8689,8 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope
   // Find the previous declaration and check that we can redeclare it.
   NamespaceAliasDecl *Prev = nullptr; 
   if (NamedDecl *PrevDecl = PrevR.getAsSingle<NamedDecl>()) {
-    if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
+    if (NamespaceAliasDecl *AD =
+            dyn_cast<NamespaceAliasDecl>(PrevR.getRepresentativeDecl())) {
       // We already have an alias with the same name that points to the same
       // namespace; check that it matches.
       if (AD->getNamespace()->Equals(getNamespaceDecl(ND))) {
@@ -8697,7 +8698,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope
       } else if (isVisible(PrevDecl)) {
         Diag(AliasLoc, diag::err_redefinition_different_namespace_alias)
           << Alias;
-        Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias)
+        Diag(AD->getLocation(), diag::note_previous_namespace_alias)
           << AD->getNamespace();
         return nullptr;
       }

Modified: cfe/trunk/test/SemaCXX/namespace-alias.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/namespace-alias.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/namespace-alias.cpp (original)
+++ cfe/trunk/test/SemaCXX/namespace-alias.cpp Tue Dec 29 17:34:32 2015
@@ -133,3 +133,27 @@ namespace PR25731 {
     X::f();
   }
 }
+
+namespace MultipleUnambiguousLookupResults {
+  namespace A { int y; }
+  namespace B {
+    namespace X { int x; }
+    namespace Y = A;
+    namespace Z = A; // expected-note {{candidate}}
+  }
+  namespace C {
+    namespace X = B::X;
+    namespace Y = A;
+    namespace Z = X; // expected-note {{candidate}}
+  }
+  using namespace B;
+  using namespace C;
+  int x1 = X::x; // ok, unambiguous
+  int y1 = Y::y; // ok, unambiguous
+  int z1 = Z::x; // expected-error {{ambiguous}}
+
+  namespace X = C::X;
+  namespace Y = A;
+  int x2 = X::x; // ok, unambiguous
+  int y2 = Y::y; // ok, unambiguous
+}

Modified: cfe/trunk/test/SemaCXX/using-decl-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-decl-1.cpp?rev=256601&r1=256600&r2=256601&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/using-decl-1.cpp (original)
+++ cfe/trunk/test/SemaCXX/using-decl-1.cpp Tue Dec 29 17:34:32 2015
@@ -30,9 +30,7 @@ struct X0 {
 };
 
 struct X1 : X0 {
-  // FIXME: give this operator() a 'float' parameter to test overloading
-  // behavior. It currently fails.
-  void operator()();
+  void operator()(float&);
   using X0::operator();
   
   void test() {




More information about the cfe-commits mailing list