r217103 - [modules] Make NamespaceAliasDecl redeclarable, as it should be. This fixes

Richard Smith richard-llvm at metafoo.co.uk
Wed Sep 3 16:11:22 PDT 2014


Author: rsmith
Date: Wed Sep  3 18:11:22 2014
New Revision: 217103

URL: http://llvm.org/viewvc/llvm-project?rev=217103&view=rev
Log:
[modules] Make NamespaceAliasDecl redeclarable, as it should be. This fixes
merging of namespace aliases across modules and improves source fidelity.
Incidentally also fixes PR20816.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Serialization/ASTCommon.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Modules/Inputs/cxx-decls-imported.h
    cfe/trunk/test/Modules/Inputs/cxx-decls-merged.h
    cfe/trunk/test/Modules/cxx-decls.cpp
    cfe/trunk/test/SemaCXX/namespace-alias.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Sep  3 18:11:22 2014
@@ -2636,7 +2636,8 @@ public:
 /// \code
 /// namespace Foo = Bar;
 /// \endcode
-class NamespaceAliasDecl : public NamedDecl {
+class NamespaceAliasDecl : public NamedDecl,
+                           public Redeclarable<NamespaceAliasDecl> {
   void anchor() override;
 
   /// \brief The location of the \c namespace keyword.
@@ -2654,17 +2655,47 @@ class NamespaceAliasDecl : public NamedD
   /// a NamespaceAliasDecl.
   NamedDecl *Namespace;
 
-  NamespaceAliasDecl(DeclContext *DC, SourceLocation NamespaceLoc,
-                     SourceLocation AliasLoc, IdentifierInfo *Alias,
-                     NestedNameSpecifierLoc QualifierLoc,
+  NamespaceAliasDecl(ASTContext &C, DeclContext *DC,
+                     SourceLocation NamespaceLoc, SourceLocation AliasLoc,
+                     IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc,
                      SourceLocation IdentLoc, NamedDecl *Namespace)
-    : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias),
-      NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
-      QualifierLoc(QualifierLoc), Namespace(Namespace) { }
+      : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C),
+        NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
+        QualifierLoc(QualifierLoc), Namespace(Namespace) {}
+
+  typedef Redeclarable<NamespaceAliasDecl> redeclarable_base;
+  NamespaceAliasDecl *getNextRedeclarationImpl() override;
+  NamespaceAliasDecl *getPreviousDeclImpl() override;
+  NamespaceAliasDecl *getMostRecentDeclImpl() override;
 
   friend class ASTDeclReader;
 
 public:
+  static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
+                                    SourceLocation NamespaceLoc,
+                                    SourceLocation AliasLoc,
+                                    IdentifierInfo *Alias,
+                                    NestedNameSpecifierLoc QualifierLoc,
+                                    SourceLocation IdentLoc,
+                                    NamedDecl *Namespace);
+
+  static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+  typedef redeclarable_base::redecl_range redecl_range;
+  typedef redeclarable_base::redecl_iterator redecl_iterator;
+  using redeclarable_base::redecls_begin;
+  using redeclarable_base::redecls_end;
+  using redeclarable_base::redecls;
+  using redeclarable_base::getPreviousDecl;
+  using redeclarable_base::getMostRecentDecl;
+
+  NamespaceAliasDecl *getCanonicalDecl() override {
+    return getFirstDecl();
+  }
+  const NamespaceAliasDecl *getCanonicalDecl() const {
+    return getFirstDecl();
+  }
+
   /// \brief Retrieve the nested-name-specifier that qualifies the
   /// name of the namespace, with source-location information.
   NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
@@ -2701,16 +2732,6 @@ public:
   /// may either be a NamespaceDecl or a NamespaceAliasDecl.
   NamedDecl *getAliasedNamespace() const { return Namespace; }
 
-  static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
-                                    SourceLocation NamespaceLoc,
-                                    SourceLocation AliasLoc,
-                                    IdentifierInfo *Alias,
-                                    NestedNameSpecifierLoc QualifierLoc,
-                                    SourceLocation IdentLoc,
-                                    NamedDecl *Namespace);
-
-  static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
   SourceRange getSourceRange() const override LLVM_READONLY {
     return SourceRange(NamespaceLoc, IdentLoc);
   }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep  3 18:11:22 2014
@@ -3887,6 +3887,10 @@ def err_redefinition_different_type : Er
   "redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
 def err_redefinition_different_kind : Error<
   "redefinition of %0 as different kind of symbol">;
+def err_redefinition_different_namespace_alias : Error<
+  "redefinition of %0 as an alias for a different namespace">;
+def note_previous_namespace_alias : Note<
+  "previously defined as an alias for %0">;
 def warn_forward_class_redefinition : Warning<
   "redefinition of forward class %0 of a typedef name of an object type is ignored">,
   InGroup<DiagGroup<"objc-forward-class-redefinition">>;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Sep  3 18:11:22 2014
@@ -1970,6 +1970,16 @@ NamespaceDecl *NamespaceDecl::getMostRec
 
 void NamespaceAliasDecl::anchor() { }
 
+NamespaceAliasDecl *NamespaceAliasDecl::getNextRedeclarationImpl() {
+  return getNextRedeclaration();
+}
+NamespaceAliasDecl *NamespaceAliasDecl::getPreviousDeclImpl() {
+  return getPreviousDecl();
+}
+NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() {
+  return getMostRecentDecl();
+}
+
 NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
                                                SourceLocation UsingLoc,
                                                SourceLocation AliasLoc,
@@ -1977,15 +1987,16 @@ NamespaceAliasDecl *NamespaceAliasDecl::
                                            NestedNameSpecifierLoc QualifierLoc,
                                                SourceLocation IdentLoc,
                                                NamedDecl *Namespace) {
+  // FIXME: Preserve the aliased namespace as written.
   if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
     Namespace = NS->getOriginalNamespace();
-  return new (C, DC) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
+  return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias,
                                         QualifierLoc, IdentLoc, Namespace);
 }
 
 NamespaceAliasDecl *
 NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
-  return new (C, ID) NamespaceAliasDecl(nullptr, SourceLocation(),
+  return new (C, ID) NamespaceAliasDecl(C, nullptr, SourceLocation(),
                                         SourceLocation(), nullptr,
                                         NestedNameSpecifierLoc(),
                                         SourceLocation(), nullptr);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Sep  3 18:11:22 2014
@@ -8264,49 +8264,50 @@ Decl *Sema::ActOnAliasDeclaration(Scope
   return NewND;
 }
 
-Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
-                                             SourceLocation NamespaceLoc,
-                                             SourceLocation AliasLoc,
-                                             IdentifierInfo *Alias,
-                                             CXXScopeSpec &SS,
-                                             SourceLocation IdentLoc,
-                                             IdentifierInfo *Ident) {
+Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
+                                   SourceLocation AliasLoc,
+                                   IdentifierInfo *Alias, CXXScopeSpec &SS,
+                                   SourceLocation IdentLoc,
+                                   IdentifierInfo *Ident) {
 
   // Lookup the namespace name.
   LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
   LookupParsedName(R, S, &SS);
 
+  if (R.isAmbiguous())
+    return nullptr;
+
+  if (R.empty()) {
+    if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
+      Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
+      return nullptr;
+    }
+  }
+  assert(!R.isAmbiguous() && !R.empty());
+
   // Check if we have a previous declaration with the same name.
-  NamedDecl *PrevDecl
-    = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, 
-                       ForRedeclaration);
+  NamedDecl *PrevDecl = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
+                                         ForRedeclaration);
   if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
     PrevDecl = nullptr;
 
   if (PrevDecl) {
     if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
       // We already have an alias with the same name that points to the same
-      // namespace, so don't create a new one.
-      // FIXME: At some point, we'll want to create the (redundant)
-      // declaration to maintain better source information.
-      if (!R.isAmbiguous() && !R.empty() &&
-          AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
+      // namespace; check that it matches.
+      if (!AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) {
+        Diag(AliasLoc, diag::err_redefinition_different_namespace_alias)
+          << Alias;
+        Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias)
+          << AD->getNamespace();
         return nullptr;
-    }
-
-    unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
-      diag::err_redefinition_different_kind;
-    Diag(AliasLoc, DiagID) << Alias;
-    Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-    return nullptr;
-  }
-
-  if (R.isAmbiguous())
-    return nullptr;
-
-  if (R.empty()) {
-    if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
-      Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
+      }
+    } else {
+      unsigned DiagID = isa<NamespaceDecl>(PrevDecl)
+                            ? diag::err_redefinition
+                            : diag::err_redefinition_different_kind;
+      Diag(AliasLoc, DiagID) << Alias;
+      Diag(PrevDecl->getLocation(), diag::note_previous_definition);
       return nullptr;
     }
   }
@@ -8315,6 +8316,8 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope
     NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
                                Alias, SS.getWithLocInContext(Context),
                                IdentLoc, R.getFoundDecl());
+  if (PrevDecl)
+    AliasDecl->setPreviousDecl(cast<NamespaceAliasDecl>(PrevDecl));
 
   PushOnScopeChains(AliasDecl, S);
   return AliasDecl;

Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.cpp Wed Sep  3 18:11:22 2014
@@ -151,7 +151,7 @@ bool serialization::isRedeclarableDeclKi
   switch (static_cast<Decl::Kind>(Kind)) {
   case Decl::TranslationUnit: // Special case of a "merged" declaration.
   case Decl::Namespace:
-  case Decl::NamespaceAlias: // FIXME: Not yet redeclarable, but will be.
+  case Decl::NamespaceAlias:
   case Decl::Typedef:
   case Decl::TypeAlias:
   case Decl::Enum:
@@ -189,8 +189,6 @@ bool serialization::isRedeclarableDeclKi
   case Decl::MSProperty:
   case Decl::ObjCIvar:
   case Decl::ObjCAtDefsField:
-  case Decl::ImplicitParam:
-  case Decl::ParmVar:
   case Decl::NonTypeTemplateParm:
   case Decl::TemplateTemplateParm:
   case Decl::Using:
@@ -213,6 +211,12 @@ bool serialization::isRedeclarableDeclKi
   case Decl::Import:
   case Decl::OMPThreadPrivate:
     return false;
+
+  // These indirectly derive from Redeclarable<T> but are not actually
+  // redeclarable.
+  case Decl::ImplicitParam:
+  case Decl::ParmVar:
+    return false;
   }
 
   llvm_unreachable("Unhandled declaration kind");

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Sep  3 18:11:22 2014
@@ -1205,11 +1205,13 @@ void ASTDeclReader::VisitNamespaceDecl(N
 }
 
 void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+  RedeclarableResult Redecl = VisitRedeclarable(D);
   VisitNamedDecl(D);
   D->NamespaceLoc = ReadSourceLocation(Record, Idx);
   D->IdentLoc = ReadSourceLocation(Record, Idx);
   D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
   D->Namespace = ReadDeclAs<NamedDecl>(Record, Idx);
+  mergeRedeclarable(D, Redecl);
 }
 
 void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
@@ -2355,10 +2357,10 @@ static bool isSameTemplateParameterList(
 /// \brief Determine whether the two declarations refer to the same entity.
 static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
   assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
-  
+
   if (X == Y)
     return true;
-  
+
   // Must be in the same context.
   if (!X->getDeclContext()->getRedeclContext()->Equals(
          Y->getDeclContext()->getRedeclContext()))
@@ -2370,11 +2372,11 @@ static bool isSameEntity(NamedDecl *X, N
     if (TypedefNameDecl *TypedefY = dyn_cast<TypedefNameDecl>(Y))
       return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
                                             TypedefY->getUnderlyingType());
-  
+
   // Must have the same kind.
   if (X->getKind() != Y->getKind())
     return false;
-    
+
   // Objective-C classes and protocols with the same name always match.
   if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
     return true;
@@ -2396,8 +2398,8 @@ static bool isSameEntity(NamedDecl *X, N
   }
 
   // Functions with the same type and linkage match.
-  // FIXME: This needs to cope with function template specializations,
-  // merging of prototyped/non-prototyped functions, etc.
+  // FIXME: This needs to cope with merging of prototyped/non-prototyped
+  // functions, etc.
   if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
     FunctionDecl *FuncY = cast<FunctionDecl>(Y);
     return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
@@ -2430,7 +2432,6 @@ static bool isSameEntity(NamedDecl *X, N
   // Fields with the same name and the same type match.
   if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
     FieldDecl *FDY = cast<FieldDecl>(Y);
-    // FIXME: Diagnose if the types don't match.
     // FIXME: Also check the bitwidth is odr-equivalent, if any.
     return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
   }
@@ -2446,6 +2447,12 @@ static bool isSameEntity(NamedDecl *X, N
     return USX->getTargetDecl() == USY->getTargetDecl();
   }
 
+  // Namespace alias definitions with the same target match.
+  if (auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
+    auto *NAY = cast<NamespaceAliasDecl>(Y);
+    return NAX->getNamespace()->Equals(NAY->getNamespace());
+  }
+
   // FIXME: Many other cases to implement.
   return false;
 }

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Sep  3 18:11:22 2014
@@ -951,6 +951,7 @@ void ASTDeclWriter::VisitNamespaceDecl(N
 }
 
 void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+  VisitRedeclarable(D);
   VisitNamedDecl(D);
   Writer.AddSourceLocation(D->getNamespaceLoc(), Record);
   Writer.AddSourceLocation(D->getTargetNameLoc(), Record);

Modified: cfe/trunk/test/Modules/Inputs/cxx-decls-imported.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-decls-imported.h?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-decls-imported.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-decls-imported.h Wed Sep  3 18:11:22 2014
@@ -44,3 +44,6 @@ typedef struct {
 } NameForLinkage2;
 auto name_for_linkage2_inner_a = NameForLinkage2::Inner();
 typedef decltype(name_for_linkage2_inner_a) NameForLinkage2Inner;
+
+namespace Aliased { extern int a; }
+namespace Alias = Aliased;

Modified: cfe/trunk/test/Modules/Inputs/cxx-decls-merged.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-decls-merged.h?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-decls-merged.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-decls-merged.h Wed Sep  3 18:11:22 2014
@@ -22,3 +22,6 @@ typedef struct {
 } NameForLinkage2;
 auto name_for_linkage2_inner_b = NameForLinkage2::Inner();
 typedef decltype(name_for_linkage2_inner_b) NameForLinkage2Inner;
+
+namespace Aliased { extern int b; }
+namespace Alias = Aliased;

Modified: cfe/trunk/test/Modules/cxx-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-decls.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/test/Modules/cxx-decls.cpp (original)
+++ cfe/trunk/test/Modules/cxx-decls.cpp Wed Sep  3 18:11:22 2014
@@ -46,6 +46,8 @@ int overrides_virtual_functions_test =
 
 void use_extern_c_function() { ExternCFunction(); }
 
+int use_namespace_alias() { return Alias::a + Alias::b; }
+
 @import cxx_decls_premerged;
 
 void use_extern_c_function_2() { ExternCFunction(); }

Modified: cfe/trunk/test/SemaCXX/namespace-alias.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/namespace-alias.cpp?rev=217103&r1=217102&r2=217103&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/namespace-alias.cpp (original)
+++ cfe/trunk/test/SemaCXX/namespace-alias.cpp Wed Sep  3 18:11:22 2014
@@ -35,12 +35,12 @@ namespace H {
   namespace A2 { }
 
   // These all point to A1.
-  namespace B = A1; // expected-note {{previous definition is here}}
+  namespace B = A1;
   namespace B = A1;
   namespace C = B;
-  namespace B = C;
+  namespace B = C; // expected-note {{previously defined as an alias for 'A1'}}
 
-  namespace B = A2; // expected-error {{redefinition of 'B' as different kind of symbol}}
+  namespace B = A2; // expected-error {{redefinition of 'B' as an alias for a different namespace}}
 }
 
 namespace I { 





More information about the cfe-commits mailing list