When instantiating the definition of a member function of a class

template, introduce that member function into the template
instantiation stack. Also, add diagnostics showing the member function
within the instantiation stack and clean up the qualified-name
printing so that we get something like:

  note: in instantiation of member function 'Switch1<int, 2, 2>::f'
  requested here

in the template instantiation backtrace.

llvm-svn: 72015
This commit is contained in:
Douglas Gregor 2009-05-18 17:01:57 +00:00
parent f811647c27
commit 8567358cc9
8 changed files with 62 additions and 36 deletions

View File

@ -745,6 +745,8 @@ def note_template_class_instantiation_here : Note<
"in instantiation of template class %0 requested here">;
def note_template_member_class_here : Note<
"in instantiation of member class %0 requested here">;
def note_template_member_function_here : Note<
"in instantiation of member function %q0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
def err_field_instantiates_to_function : Error<

View File

@ -212,7 +212,15 @@ std::string NamedDecl::getQualifiedNameAsString() const {
// scope class/struct/union. How do we handle this case?
break;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size());
Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr);
} else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
Names.push_back(ND->getNameAsString());
else
break;

View File

@ -2070,9 +2070,10 @@ public:
/// Destruction of this object will pop the named instantiation off
/// the stack.
struct InstantiatingTemplate {
/// \brief Note that we are instantiating a class template.
/// \brief Note that we are instantiating a class template,
/// function template, or a member thereof.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
CXXRecordDecl *Entity,
Decl *Entity,
SourceRange InstantiationRange = SourceRange());
/// \brief Note that we are instantiating a default argument in a
@ -2083,7 +2084,10 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
~InstantiatingTemplate();
/// \brief Note that we have finished instantiating this template.
void Clear();
~InstantiatingTemplate() { Clear(); }
/// \brief Determines whether we have exceeded the maximum
/// recursive template instantiations.
@ -2216,7 +2220,8 @@ public:
InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(FunctionDecl *Function);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function);
void InstantiateVariableDefinition(VarDecl *Var);
// Simple function for cloning expressions.

View File

@ -2340,11 +2340,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// instantiation.
if (SpecializationRequiresInstantiation)
InstantiateClassTemplateSpecialization(Specialization, true);
else {
// Instantiate the members of this class template specialization.
InstantiatingTemplate Inst(*this, TemplateLoc, Specialization);
else // Instantiate the members of this class template specialization.
InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
}
return DeclPtrTy::make(Specialization);
}
@ -2405,12 +2402,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
getTemplateInstantiationArgs(Record),
/*ExplicitInstantiation=*/true))
return true;
} else {
// Instantiate all of the members of class.
InstantiatingTemplate Inst(*this, TemplateLoc, Record);
} else // Instantiate all of the members of class.
InstantiateClassMembers(TemplateLoc, Record,
getTemplateInstantiationArgs(Record));
}
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it

View File

@ -46,7 +46,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
CXXRecordDecl *Entity,
Decl *Entity,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
@ -89,9 +89,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
Sema::InstantiatingTemplate::~InstantiatingTemplate() {
if (!Invalid)
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
}
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
@ -120,14 +122,24 @@ void Sema::PrintInstantiationStack() {
++Active) {
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
unsigned DiagID = diag::note_template_member_class_here;
CXXRecordDecl *Record = (CXXRecordDecl *)Active->Entity;
if (isa<ClassTemplateSpecializationDecl>(Record))
DiagID = diag::note_template_class_instantiation_here;
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Context.getTypeDeclType(Record)
<< Active->InstantiationRange;
Decl *D = reinterpret_cast<Decl *>(Active->Entity);
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
unsigned DiagID = diag::note_template_member_class_here;
if (isa<ClassTemplateSpecializationDecl>(Record))
DiagID = diag::note_template_class_instantiation_here;
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Context.getTypeDeclType(Record)
<< Active->InstantiationRange;
} else {
FunctionDecl *Function = cast<FunctionDecl>(D);
unsigned DiagID = diag::note_template_member_function_here;
// FIXME: check for a function template
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
DiagID)
<< Function
<< Active->InstantiationRange;
}
break;
}
@ -768,8 +780,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CurContext = PreviousContext;
// If this is an explicit instantiation, instantiate our members, too.
if (!Invalid && ExplicitInstantiation)
if (!Invalid && ExplicitInstantiation) {
Inst.Clear();
InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
}
return Invalid;
}
@ -820,7 +834,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
if (!Function->getBody(Context))
InstantiateFunctionDefinition(Function);
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
const VarDecl *Def = 0;
if (!Var->getDefinition(Def))
@ -829,7 +843,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
InstantiateClass(Record->getLocation(), Record,
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
TemplateArgs, true);
}

View File

@ -574,7 +574,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
///
/// \param Function the already-instantiated declaration of a
/// function.
void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) {
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function) {
// FIXME: make this work for function template specializations, too.
if (Function->isInvalidDecl())
@ -590,7 +591,9 @@ void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) {
if (!Pattern)
return;
// FIXME: add to the instantiation stack.
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));

View File

@ -1,4 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
// RUN: clang-cc -fsyntax-only %s
template<typename T, typename U>
struct X0 {
void f(T x, U y) {
@ -47,8 +47,8 @@ template <typename T> struct X4 {
}
};
template struct X4<void>; // expected-note{{in instantiation of template class 'X4<void>' requested here}}
template struct X4<int>; // expected-note{{in instantiation of template class 'X4<int>' requested here}}
template struct X4<void>; // expected-note{{in instantiation of}}
template struct X4<int>; // expected-note{{in instantiation of}}
struct Incomplete; // expected-note{{forward declaration}}

View File

@ -49,7 +49,7 @@ 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}}
struct Inner {
void f(T*); // expected-error{{pointer to a reference}}
};
};
@ -59,8 +59,8 @@ 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}}
struct Inner {
struct VeryInner {
void f(T*); // expected-error 2{{pointer to a reference}}
};
};
@ -82,7 +82,7 @@ struct X5 {
};
struct Inner2 {
struct VeryInner { // expected-note 2{{instantiation}}
struct VeryInner {
void g(T*); // expected-error 2{{pointer to a reference}}
};
};