r192740 - C++ modules: merging for enumerations and enumerators with multiple definitions

Richard Smith richard-llvm at metafoo.co.uk
Tue Oct 15 15:02:41 PDT 2013


Author: rsmith
Date: Tue Oct 15 17:02:41 2013
New Revision: 192740

URL: http://llvm.org/viewvc/llvm-project?rev=192740&view=rev
Log:
C++ modules: merging for enumerations and enumerators with multiple definitions
(eg through template instantiations in multiple modules).

Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/test/Modules/Inputs/cxx-templates-a.h
    cfe/trunk/test/Modules/Inputs/cxx-templates-b.h
    cfe/trunk/test/Modules/Inputs/cxx-templates-common.h
    cfe/trunk/test/Modules/cxx-templates.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Oct 15 17:02:41 2013
@@ -2242,7 +2242,7 @@ public:
 /// that is defined.  For example, in "enum X {a,b}", each of a/b are
 /// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
 /// TagType for the X EnumDecl.
-class EnumConstantDecl : public ValueDecl {
+class EnumConstantDecl : public ValueDecl, public Mergeable<EnumConstantDecl> {
   Stmt *Init; // an integer constant expression
   llvm::APSInt Val; // The value.
 protected:
@@ -2268,6 +2268,14 @@ public:
 
   SourceRange getSourceRange() const LLVM_READONLY;
 
+  /// Retrieves the canonical declaration of this enumerator.
+  EnumConstantDecl *getCanonicalDecl() {
+    return getFirstDeclaration();
+  }
+  const EnumConstantDecl *getCanonicalDecl() const {
+    return getFirstDeclaration();
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == EnumConstant; }

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Tue Oct 15 17:02:41 2013
@@ -917,6 +917,10 @@ private:
   /// when merging implicit instantiations of class templates across modules.
   llvm::DenseMap<DeclContext *, DeclContext *> MergedDeclContexts;
 
+  /// \brief A mapping from canonical declarations of enums to their canonical
+  /// definitions. Only populated when using modules in C++.
+  llvm::DenseMap<EnumDecl *, EnumDecl *> EnumDefinitions;
+
   /// \brief When reading a Stmt tree, Stmt operands are placed in this stack.
   SmallVector<Stmt *, 16> StmtStack;
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Oct 15 17:02:41 2013
@@ -488,6 +488,19 @@ void ASTDeclReader::VisitEnumDecl(EnumDe
   ED->IsScopedUsingClassTag = Record[Idx++];
   ED->IsFixed = Record[Idx++];
 
+  // If this is a definition subject to the ODR, and we already have a
+  // definition, merge this one into it.
+  if (ED->IsCompleteDefinition &&
+      Reader.getContext().getLangOpts().Modules &&
+      Reader.getContext().getLangOpts().CPlusPlus) {
+    if (EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]) {
+      Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef));
+      ED->IsCompleteDefinition = false;
+    } else {
+      OldDef = ED;
+    }
+  }
+
   if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
     TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
     SourceLocation POI = ReadSourceLocation(Record, Idx);
@@ -516,6 +529,7 @@ void ASTDeclReader::VisitEnumConstantDec
   if (Record[Idx++])
     ECD->setInitExpr(Reader.ReadExpr(F));
   ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
+  mergeMergeable(ECD);
 }
 
 void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
@@ -1893,6 +1907,12 @@ void ASTDeclReader::mergeMergeable(Merge
   if (!Reader.getContext().getLangOpts().Modules)
     return;
 
+  // ODR-based merging is only performed in C++. In C, identically-named things
+  // in different translation units are not redeclarations (but may still have
+  // compatible types).
+  if (!Reader.getContext().getLangOpts().CPlusPlus)
+    return;
+
   if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
     if (T *Existing = ExistingRes)
       Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D),
@@ -2122,9 +2142,15 @@ static bool isSameEntity(NamedDecl *X, N
     // FIXME: Diagnose if the types don't match. More generally, diagnose if we
     // get a declaration in a class definition that isn't in the canonical class
     // definition.
+    // FIXME: Also check the bitwidth is odr-equivalent, if any.
     return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
   }
 
+  // Enumerators with the same name match.
+  if (isa<EnumConstantDecl>(X))
+    // FIXME: Also check the value is odr-equivalent.
+    return true;
+
   // FIXME: Many other cases to implement.
   return false;
 }
@@ -2138,6 +2164,9 @@ static DeclContext *getPrimaryContextFor
   if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
     return RD->getDefinition();
 
+  if (EnumDecl *ED = dyn_cast<EnumDecl>(DC))
+    return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition() : 0;
+
   return 0;
 }
 

Modified: cfe/trunk/test/Modules/Inputs/cxx-templates-a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-templates-a.h?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-templates-a.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-templates-a.h Tue Oct 15 17:02:41 2013
@@ -33,3 +33,10 @@ void use_some_template_a() {
 
 template<int> struct MergeTemplates;
 MergeTemplates<0> *merge_templates_a;
+
+auto enum_a_from_a = CommonTemplate<int>::a;
+const auto enum_c_from_a = CommonTemplate<int>::c;
+
+template<int> struct UseInt;
+template<typename T> void UseRedeclaredEnum(UseInt<T() + CommonTemplate<char>::a>);
+constexpr void (*UseRedeclaredEnumA)(UseInt<1>) = UseRedeclaredEnum<int>;

Modified: cfe/trunk/test/Modules/Inputs/cxx-templates-b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-templates-b.h?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-templates-b.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-templates-b.h Tue Oct 15 17:02:41 2013
@@ -44,6 +44,13 @@ void use_some_template_b() {
   b = c;
 }
 
+auto enum_b_from_b = CommonTemplate<int>::b;
+const auto enum_c_from_b = CommonTemplate<int>::c;
+
+template<int> struct UseInt;
+template<typename T> void UseRedeclaredEnum(UseInt<T() + CommonTemplate<char>::a>);
+constexpr void (*UseRedeclaredEnumB)(UseInt<1>) = UseRedeclaredEnum<int>;
+
 @import cxx_templates_a;
 template<typename T> void UseDefinedInBImplIndirectly(T &v) {
   PerformDelayedLookup(v);

Modified: cfe/trunk/test/Modules/Inputs/cxx-templates-common.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-templates-common.h?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-templates-common.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-templates-common.h Tue Oct 15 17:02:41 2013
@@ -5,3 +5,7 @@ struct DefinedInCommon {
   struct Inner {};
   friend void FoundByADL(DefinedInCommon);
 };
+
+template<typename T> struct CommonTemplate {
+  enum E { a = 1, b = 2, c = 3 };
+};

Modified: cfe/trunk/test/Modules/cxx-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=192740&r1=192739&r2=192740&view=diff
==============================================================================
--- cfe/trunk/test/Modules/cxx-templates.cpp (original)
+++ cfe/trunk/test/Modules/cxx-templates.cpp Tue Oct 15 17:02:41 2013
@@ -5,6 +5,7 @@
 
 @import cxx_templates_a;
 @import cxx_templates_b;
+ at import cxx_templates_common;
 
 template<typename, char> struct Tmpl_T_C {};
 template<typename, int, int> struct Tmpl_T_I_I {};
@@ -12,6 +13,8 @@ template<typename, int, int> struct Tmpl
 template<typename A, typename B, A> struct Tmpl_T_T_A {};
 template<typename A, typename B, B> struct Tmpl_T_T_B {};
 
+template<int> struct UseInt {};
+
 void g() {
   f(0);
   f<double>(1.0);
@@ -71,6 +74,19 @@ void g() {
   PerformDelayedLookup(defined_in_b_impl); // expected-note {{in instantiation of}}
 
   merge_templates_a = merge_templates_b; // ok, same type
+
+  using T = decltype(enum_a_from_a);
+  using T = decltype(enum_b_from_b);
+  T e = true ? enum_a_from_a : enum_b_from_b;
+
+  UseRedeclaredEnum<int>(UseInt<1>());
+  // FIXME: Reintroduce this once we merge function template specializations.
+  //static_assert(UseRedeclaredEnumA == UseRedeclaredEnumB, "");
+  //static_assert(UseRedeclaredEnumA == UseRedeclaredEnum<int>, "");
+  //static_assert(UseRedeclaredEnumB == UseRedeclaredEnum<int>, "");
+  static_assert(enum_c_from_a == enum_c_from_b, "");
+  CommonTemplate<int> cti;
+  CommonTemplate<int>::E eee = CommonTemplate<int>::c;
 }
 
 RedeclaredAsFriend<int> raf1;





More information about the cfe-commits mailing list