Explicit instantiations of templates now instantiate the definitions

of class members (recursively). Only member classes are actually
instantiated; the instantiation logic for member functions and
variables are just stubs.

llvm-svn: 71713
This commit is contained in:
Douglas Gregor 2009-05-13 20:28:22 +00:00
parent 5879fbd933
commit bbbb02d463
5 changed files with 109 additions and 4 deletions

View File

@ -2116,6 +2116,14 @@ public:
ClassTemplateSpecializationDecl *ClassTemplateSpec,
bool ExplicitInstantiation);
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const TemplateArgumentList &TemplateArgs);
void InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec);
NestedNameSpecifier *
InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range,
@ -2125,6 +2133,9 @@ public:
InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(FunctionDecl *Function);
void InstantiateVariableDefinition(VarDecl *Var);
// Simple function for cloning expressions.
template<typename T>
OwningExprResult Clone(T *E) {

View File

@ -2335,9 +2335,10 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
InstantiateClassTemplateSpecialization(Specialization, true))
return true;
// FIXME: Instantiate all of the members of the template (that
// haven't already been instantiated!).
// Instantiate the members of this class template specialization.
InstantiatingTemplate Inst(*this, TemplateLoc, Specialization);
InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
return DeclPtrTy::make(Specialization);
}

View File

@ -749,6 +749,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
CurContext = PreviousContext;
// If this is an explicit instantiation, instantiate our members, too.
if (!Invalid && ExplicitInstantiation)
InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
return Invalid;
}
@ -787,6 +791,53 @@ Sema::InstantiateClassTemplateSpecialization(
ExplicitInstantiation);
}
/// \brief Instantiate the definitions of all of the member of the
/// given class, which is an instantiation of a class template or a
/// member class of a template.
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const TemplateArgumentList &TemplateArgs) {
for (DeclContext::decl_iterator D = Instantiation->decls_begin(Context),
DEnd = Instantiation->decls_end(Context);
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
if (!Function->getBody(Context))
InstantiateFunctionDefinition(Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
const VarDecl *Def = 0;
if (!Var->getDefinition(Def))
InstantiateVariableDefinition(Var);
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
InstantiateClass(Record->getLocation(), Record,
Record->getInstantiatedFromMemberClass(),
TemplateArgs, true);
}
}
}
}
/// \brief Instantiate the definitions of all of the members of the
/// given class template specialization, which was named as part of an
/// explicit instantiation.
void Sema::InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec) {
// C++0x [temp.explicit]p7:
// An explicit instantiation that names a class template
// specialization is an explicit instantion of the same kind
// (declaration or definition) of each of its members (not
// including members inherited from base classes) that has not
// been previously explicitly specialized in the translation unit
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
ClassTemplateSpec->getTemplateArgs());
}
/// \brief Instantiate a nested-name-specifier.
NestedNameSpecifier *
Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,

View File

@ -550,3 +550,20 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
// FIXME: New needs a pointer to Tmpl
return false;
}
/// \brief Instantiate the definition of the given function from its
/// template.
///
/// \param Function the already-instantiated declaration of a
/// function.
void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) {
// FIXME: Implement this!
}
/// \brief Instantiate the definition of the given variable from its
/// template.
///
/// \param Var the already-instantiated declaration of a variable.
void Sema::InstantiateVariableDefinition(VarDecl *Var) {
// FIXME: Implement this!
}

View File

@ -1,4 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify -pedantic %s
// RUN: clang-cc -fsyntax-only -pedantic -verify %s
//
// Tests explicit instantiation of templates.
template<typename T, typename U = T> class X0 { };
@ -46,3 +46,28 @@ struct X2 {
template struct X2<int>; // okay
template struct X2<int&>; // expected-note{{in instantiation of}}
// Check that explicit instantiations instantiate member classes.
template<typename T> struct X3 {
struct Inner { // expected-note{{here}}
void f(T*); // expected-error{{pointer to a reference}}
};
};
void f1(X3<int&>); // okay, Inner, not instantiated
template struct X3<int&>; // expected-note{{instantiation}}
template<typename T> struct X4 {
struct Inner { // expected-note 2{{here}}
struct VeryInner { // expected-note 2{{here}}
void f(T*); // expected-error 2{{pointer to a reference}}
};
};
};
void f2(X4<int&>); // okay, Inner, not instantiated
void f3(X4<int&>::Inner); // okay, Inner::VeryInner, not instantiated
template struct X4<int&>; // expected-note{{instantiation}}
template struct X4<float&>; // expected-note{{instantiation}}