mirror of
https://github.com/intel/llvm.git
synced 2026-02-02 02:00:03 +08:00
C++ modules: merging for enumerations and enumerators with multiple definitions
(eg through template instantiations in multiple modules). llvm-svn: 192740
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -488,6 +488,19 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
|
||||
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::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
|
||||
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(Mergeable<T> *D) {
|
||||
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, NamedDecl *Y) {
|
||||
// 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 *getPrimaryContextForMerging(DeclContext *DC) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
@import cxx_templates_a;
|
||||
@import cxx_templates_b;
|
||||
@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_T_I_I {};
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user