diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9397,14 +9397,21 @@ /// eagerly. SmallVector LateParsedInstantiations; + SmallVector, 8> SavedVTableUses; + SmallVector, 8> + SavedPendingInstantiations; + class GlobalEagerInstantiationScope { public: GlobalEagerInstantiationScope(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; - SavedPendingInstantiations.swap(S.PendingInstantiations); - SavedVTableUses.swap(S.VTableUses); + S.SavedPendingInstantiations.emplace_back(); + S.SavedPendingInstantiations.back().swap(S.PendingInstantiations); + + S.SavedVTableUses.emplace_back(); + S.SavedVTableUses.back().swap(S.VTableUses); } void perform() { @@ -9420,26 +9427,28 @@ // Restore the set of pending vtables. assert(S.VTableUses.empty() && "VTableUses should be empty before it is discarded."); - S.VTableUses.swap(SavedVTableUses); + S.VTableUses.swap(S.SavedVTableUses.back()); + S.SavedVTableUses.pop_back(); // Restore the set of pending implicit instantiations. if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) { assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); - S.PendingInstantiations.swap(SavedPendingInstantiations); + S.PendingInstantiations.swap(S.SavedPendingInstantiations.back()); + S.SavedPendingInstantiations.pop_back(); } else { // Template instantiations in the PCH may be delayed until the TU. - S.PendingInstantiations.swap(SavedPendingInstantiations); - S.PendingInstantiations.insert(S.PendingInstantiations.end(), - SavedPendingInstantiations.begin(), - SavedPendingInstantiations.end()); + S.PendingInstantiations.swap(S.SavedPendingInstantiations.back()); + S.PendingInstantiations.insert( + S.PendingInstantiations.end(), + S.SavedPendingInstantiations.back().begin(), + S.SavedPendingInstantiations.back().end()); + S.SavedPendingInstantiations.pop_back(); } } private: Sema &S; - SmallVector SavedVTableUses; - std::deque SavedPendingInstantiations; bool Enabled; }; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19375,6 +19375,18 @@ // multiple times. SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); + } else { + for (auto &I : SemaRef.SavedPendingInstantiations) { + auto Iter = llvm::find_if( + I, [Var](const Sema::PendingImplicitInstantiation &P) { + return P.first == Var; + }); + if (Iter != I.end()) { + SemaRef.PendingInstantiations.push_back(*Iter); + I.erase(Iter); + break; + } + } } } } diff --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp --- a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp +++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -29,10 +29,34 @@ // ALL: @_ZN1AIbE1aE ={{.*}} global i32 10 template<> int A::a = 10; -// ALL: @llvm.global_ctors = appending global [8 x { i32, void ()*, i8* }] +// ALL: @llvm.global_ctors = appending global [16 x { i32, void ()*, i8* }] -// ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) }, -// MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null }, +// ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered10:[^,]*]], i8* bitcast (i32* @_ZN3FibILi2EE1aE to i8*) }, +// MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered10:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered9:[^,]*]], i8* bitcast (i32* @_ZN3FibILi3EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered9:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered11:[^,]*]], i8* bitcast (i32* @_ZN3FibILi4EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered11:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered8:[^,]*]], i8* bitcast (i32* @_ZN3FibILi5EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered8:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered14:[^,]*]], i8* bitcast (i32* @_ZN4Fib2ILi2EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered14:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered15:[^,]*]], i8* bitcast (i32* @_ZN4Fib2ILi3EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered15:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered13:[^,]*]], i8* bitcast (i32* @_ZN4Fib2ILi4EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered13:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered12:[^,]*]], i8* bitcast (i32* @_ZN4Fib2ILi5EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered12:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null }, // ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) }, // MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* null }, @@ -54,7 +78,7 @@ // ALL: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }] /// llvm.used ensures SHT_INIT_ARRAY in a section group cannot be GCed. -// ELF: @llvm.used = appending global [6 x i8*] [i8* bitcast (i32* @_ZN1AIsE1aE to i8*), i8* bitcast (i16* @_Z1xIsE to i8*), i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*), i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*), i8* bitcast (i32* @_ZN1AIvE1aE to i8*), i8* @_Z1xIcE] +// ELF: @llvm.used = appending global [14 x i8*] [i8* bitcast (i32* @_ZN1AIsE1aE to i8*), i8* bitcast (i16* @_Z1xIsE to i8*), i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*), i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*), i8* bitcast (i32* @_ZN1AIvE1aE to i8*), i8* @_Z1xIcE, i8* bitcast (i32* @_ZN3FibILi5EE1aE to i8*), i8* bitcast (i32* @_ZN3FibILi3EE1aE to i8*), i8* bitcast (i32* @_ZN3FibILi2EE1aE to i8*), i8* bitcast (i32* @_ZN3FibILi4EE1aE to i8*), i8* bitcast (i32* @_ZN4Fib2ILi5EE1aE to i8*), i8* bitcast (i32* @_ZN4Fib2ILi4EE1aE to i8*), i8* bitcast (i32* @_ZN4Fib2ILi2EE1aE to i8*), i8* bitcast (i32* @_ZN4Fib2ILi3EE1aE to i8*)] template int A::a; // Unordered int b = foo(); @@ -94,6 +118,18 @@ } int *use_internal_a = &Internal::a; +template struct Fib { static int a; }; +template<> int Fib<0>::a = 0; +template<> int Fib<1>::a = 1; +template int Fib::a = Fib::a + Fib::a; +int f = Fib<5>::a; + +template struct Fib2 { static int a; }; +template<> int Fib2<0>::a = 0; +template<> int Fib2<1>::a = 1; +template int Fib2::a = Fib2::a + Fib2::a; +int f2 = Fib2<5>::a; + #endif // ALL: define internal void @[[unordered1]]( @@ -131,6 +167,38 @@ // ALL: store {{.*}} @_ZN12_GLOBAL__N_18InternalIiE1aE // ALL: ret +// ALL: define internal void @[[unordered8]]( +// ALL: store {{.*}} @_ZN3FibILi5EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered9]]( +// ALL: store {{.*}} @_ZN3FibILi3EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered10]]( +// ALL: store {{.*}} @_ZN3FibILi2EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered11]]( +// ALL: store {{.*}} @_ZN3FibILi4EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered12]]( +// ALL: store {{.*}} @_ZN4Fib2ILi5EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered13]]( +// ALL: store {{.*}} @_ZN4Fib2ILi4EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered14]]( +// ALL: store {{.*}} @_ZN4Fib2ILi2EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered15]]( +// ALL: store {{.*}} @_ZN4Fib2ILi3EE1aE +// ALL: ret + // ALL: define internal void @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp() // We call unique stubs for every ordered dynamic initializer in the TU. // ALL: call @@ -141,5 +209,7 @@ // ALL: call // ALL: call // ALL: call +// ALL: call +// ALL: call // ALL-NOT: call // ALL: ret