Skip to content

Commit cfe41db

Browse files
committed
Support explicit instantiation of function templates and members of class
templates when only the declaration is in scope. This requires deferring the instantiation to be lazy, and ensuring the definition is required for that translation unit. We re-use the existing pending instantiation queue, previously only used to track implicit instantiations which were required to be lazy. Fixes PR7979. A subsequent change will rename *PendingImplicitInstantiations to *PendingInstatiations for clarity given its broader role. llvm-svn: 112037
1 parent 6b1533a commit cfe41db

File tree

4 files changed

+83
-13
lines changed

4 files changed

+83
-13
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5071,8 +5071,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
50715071
// Instantiate static data member.
50725072
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
50735073
if (TSK == TSK_ExplicitInstantiationDefinition)
5074-
InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false,
5075-
/*DefinitionRequired=*/true);
5074+
InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev);
50765075

50775076
// FIXME: Create an ExplicitInstantiation node?
50785077
return (Decl*) 0;
@@ -5179,8 +5178,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
51795178
Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
51805179

51815180
if (TSK == TSK_ExplicitInstantiationDefinition)
5182-
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization,
5183-
false, /*DefinitionRequired=*/true);
5181+
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
51845182

51855183
// C++0x [temp.explicit]p2:
51865184
// If the explicit instantiation is for a member function, a member class

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,8 +2040,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
20402040
Diag(PatternDecl->getLocation(),
20412041
diag::note_explicit_instantiation_here);
20422042
Function->setInvalidDecl();
2043+
} else if (Function->getTemplateSpecializationKind()
2044+
== TSK_ExplicitInstantiationDefinition) {
2045+
PendingImplicitInstantiations.push_back(
2046+
std::make_pair(Function, PointOfInstantiation));
20432047
}
2044-
2048+
20452049
return;
20462050
}
20472051

@@ -2176,8 +2180,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
21762180
diag::err_explicit_instantiation_undefined_member)
21772181
<< 2 << Var->getDeclName() << Var->getDeclContext();
21782182
Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
2179-
}
2180-
2183+
} else if (Var->getTemplateSpecializationKind()
2184+
== TSK_ExplicitInstantiationDefinition) {
2185+
PendingImplicitInstantiations.push_back(
2186+
std::make_pair(Var, PointOfInstantiation));
2187+
}
2188+
21812189
return;
21822190
}
21832191

@@ -2714,8 +2722,10 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
27142722
Function->getLocation(), *this,
27152723
Context.getSourceManager(),
27162724
"instantiating function definition");
2717-
2718-
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
2725+
bool DefinitionRequired = Function->getTemplateSpecializationKind() ==
2726+
TSK_ExplicitInstantiationDefinition;
2727+
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
2728+
DefinitionRequired);
27192729
continue;
27202730
}
27212731

@@ -2734,9 +2744,12 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
27342744
case TSK_Undeclared:
27352745
assert(false && "Cannot instantitiate an undeclared specialization.");
27362746
case TSK_ExplicitInstantiationDeclaration:
2737-
case TSK_ExplicitInstantiationDefinition:
27382747
case TSK_ExplicitSpecialization:
2739-
continue; // No longer need implicit instantiation.
2748+
continue; // No longer need to instantiate this type.
2749+
case TSK_ExplicitInstantiationDefinition:
2750+
// We only need an instantiation if the pending instantiation *is* the
2751+
// explicit instantiation.
2752+
if (Var != Var->getMostRecentDeclaration()) continue;
27402753
case TSK_ImplicitInstantiation:
27412754
break;
27422755
}
@@ -2746,7 +2759,10 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
27462759
"instantiating static data member "
27472760
"definition");
27482761

2749-
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
2762+
bool DefinitionRequired = Var->getTemplateSpecializationKind() ==
2763+
TSK_ExplicitInstantiationDefinition;
2764+
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
2765+
DefinitionRequired);
27502766
}
27512767
}
27522768

clang/test/CXX/temp/temp.spec/temp.explicit/p3.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
// A declaration of a function template shall be in scope at the point of the
44
// explicit instantiation of the function template.
5-
template<typename T> void f0(T) { }
5+
template<typename T> void f0(T);
66
template void f0(int); // okay
7+
template<typename T> void f0(T) { }
78

89
// A definition of the class or class template containing a member function
910
// template shall be in scope at the point of the explicit instantiation of
@@ -47,3 +48,27 @@ template X2<int>::X2(); // expected-error{{not an instantiation}}
4748
template X2<int>::X2(const X2&); // expected-error{{not an instantiation}}
4849
template X2<int>::~X2(); // expected-error{{not an instantiation}}
4950
template X2<int> &X2<int>::operator=(const X2<int>&); // expected-error{{not an instantiation}}
51+
52+
53+
// A definition of a class template is sufficient to explicitly
54+
// instantiate a member of the class template which itself is not yet defined.
55+
namespace PR7979 {
56+
template <typename T> struct S {
57+
void f();
58+
static void g();
59+
static int i;
60+
struct S2 {
61+
void h();
62+
};
63+
};
64+
65+
template void S<int>::f();
66+
template void S<int>::g();
67+
template int S<int>::i;
68+
template void S<int>::S2::h();
69+
70+
template <typename T> void S<T>::f() {}
71+
template <typename T> void S<T>::g() {}
72+
template <typename T> int S<T>::i;
73+
template <typename T> void S<T>::S2::h() {}
74+
}

clang/test/CodeGenCXX/explicit-instantiation.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
22

3+
// This check logically is attached to 'template int S<int>::i;' below.
4+
// CHECK: @_ZN1SIiE1iE = weak global i32
5+
36
template<typename T, typename U, typename Result>
47
struct plus {
58
Result operator()(const T& t, const U& u) const;
@@ -12,3 +15,31 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
1215

1316
// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
1417
template struct plus<int, long, long>;
18+
19+
// Check that we emit definitions from explicit instantiations even when they
20+
// occur prior to the definition itself.
21+
template <typename T> struct S {
22+
void f();
23+
static void g();
24+
static int i;
25+
struct S2 {
26+
void h();
27+
};
28+
};
29+
30+
// CHECK: define weak_odr void @_ZN1SIiE1fEv
31+
template void S<int>::f();
32+
33+
// CHECK: define weak_odr void @_ZN1SIiE1gEv
34+
template void S<int>::g();
35+
36+
// See the check line at the top of the file.
37+
template int S<int>::i;
38+
39+
// CHECK: define weak_odr void @_ZN1SIiE2S21hEv
40+
template void S<int>::S2::h();
41+
42+
template <typename T> void S<T>::f() {}
43+
template <typename T> void S<T>::g() {}
44+
template <typename T> int S<T>::i;
45+
template <typename T> void S<T>::S2::h() {}

0 commit comments

Comments
 (0)