Clean up our handling of local instantiation scopes, which keep track
of the mapping from local declarations to their instantiated counterparts during template instantiation. Previously, we tried to do some unholy merging of local instantiation scopes that involved storing a single hash table along with an "undo" list on the side... which was ugly, and never handled function parameters properly. Now, we just keep separate hash tables for each local instantiation scope, and "combining" two scopes means that we'll look in each of the combined hash tables. The combined scope stack is rarely deep, and this makes it easy to avoid the "undo" issues we were hitting. Also, I've simplified the logic for function parameters: if we're declaring a function and we need the function parameters to live longer, we just push them back into the local instantiation scope where we need them. Fixes PR6990. llvm-svn: 102732
This commit is contained in:
parent
be474734a5
commit
14cf752486
|
@ -3589,7 +3589,7 @@ public:
|
|||
/// instantiated ParmVarDecl for 'x'.
|
||||
llvm::DenseMap<const Decl *, Decl *> LocalDecls;
|
||||
|
||||
/// \brief The outer scope, in which contains local variable
|
||||
/// \brief The outer scope, which contains local variable
|
||||
/// definitions from some other instantiation (that may not be
|
||||
/// relevant to this particular scope).
|
||||
LocalInstantiationScope *Outer;
|
||||
|
@ -3597,54 +3597,36 @@ public:
|
|||
/// \brief Whether we have already exited this scope.
|
||||
bool Exited;
|
||||
|
||||
/// \brief Whether this scope is temporary, meaning that we should
|
||||
/// remove any additions we make once we exit this
|
||||
/// scope. Temporary scopes are always combined with their outer
|
||||
/// scopes.
|
||||
bool Temporary;
|
||||
|
||||
/// \brief List of the declarations that we have added into this
|
||||
/// temporary scope. They will be removed when we exit the
|
||||
/// temporary scope.
|
||||
llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
|
||||
|
||||
/// \brief Whether to combine this scope with the outer scope, such that
|
||||
/// lookup will search our outer scope.
|
||||
bool CombineWithOuterScope;
|
||||
|
||||
// This class is non-copyable
|
||||
LocalInstantiationScope(const LocalInstantiationScope &);
|
||||
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
|
||||
|
||||
public:
|
||||
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
|
||||
bool Temporary = false)
|
||||
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
|
||||
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
|
||||
Exited(false), Temporary(Temporary) {
|
||||
if (!CombineWithOuterScope && !Temporary)
|
||||
SemaRef.CurrentInstantiationScope = this;
|
||||
else
|
||||
assert(SemaRef.CurrentInstantiationScope &&
|
||||
"No outer instantiation scope?");
|
||||
Exited(false), CombineWithOuterScope(CombineWithOuterScope)
|
||||
{
|
||||
SemaRef.CurrentInstantiationScope = this;
|
||||
}
|
||||
|
||||
~LocalInstantiationScope() {
|
||||
if (!Exited) {
|
||||
SemaRef.CurrentInstantiationScope = Outer;
|
||||
for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
|
||||
LocalDecls.erase(AddedTemporaryDecls[I]);
|
||||
}
|
||||
Exit();
|
||||
}
|
||||
|
||||
/// \brief Exit this local instantiation scope early.
|
||||
void Exit() {
|
||||
if (Exited)
|
||||
return;
|
||||
|
||||
SemaRef.CurrentInstantiationScope = Outer;
|
||||
LocalDecls.clear();
|
||||
Exited = true;
|
||||
}
|
||||
|
||||
Decl *getInstantiationOf(const Decl *D) {
|
||||
Decl *Result = LocalDecls[D];
|
||||
assert((Result || D->isInvalidDecl()) &&
|
||||
"declaration was not instantiated in this scope!");
|
||||
return Result;
|
||||
}
|
||||
Decl *getInstantiationOf(const Decl *D);
|
||||
|
||||
VarDecl *getInstantiationOf(const VarDecl *Var) {
|
||||
return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
|
||||
|
@ -3659,15 +3641,7 @@ public:
|
|||
return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var)));
|
||||
}
|
||||
|
||||
void InstantiatedLocal(const Decl *D, Decl *Inst) {
|
||||
Decl *&Stored = LocalDecls[D];
|
||||
assert((!Stored || Stored == Inst) && "Already instantiated this local");
|
||||
|
||||
if (Temporary && !Stored)
|
||||
AddedTemporaryDecls.push_back(D);
|
||||
|
||||
Stored = Inst;
|
||||
}
|
||||
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
||||
};
|
||||
|
||||
/// \brief The current instantiation scope used to store local
|
||||
|
|
|
@ -5335,6 +5335,8 @@ namespace {
|
|||
DeclarationName Entity;
|
||||
|
||||
public:
|
||||
typedef TreeTransform<CurrentInstantiationRebuilder> inherited;
|
||||
|
||||
CurrentInstantiationRebuilder(Sema &SemaRef,
|
||||
SourceLocation Loc,
|
||||
DeclarationName Entity)
|
||||
|
@ -5370,7 +5372,7 @@ namespace {
|
|||
/// FIXME: This is completely unsafe; we will need to actually clone the
|
||||
/// expressions.
|
||||
Sema::OwningExprResult TransformExpr(Expr *E) {
|
||||
return getSema().Owned(E);
|
||||
return getSema().Owned(E->Retain());
|
||||
}
|
||||
|
||||
/// \brief Transforms a typename type by determining whether the type now
|
||||
|
|
|
@ -532,8 +532,7 @@ bool Sema::isSFINAEContext() const {
|
|||
// Template Instantiation for Types
|
||||
//===----------------------------------------------------------------------===/
|
||||
namespace {
|
||||
class TemplateInstantiator
|
||||
: public TreeTransform<TemplateInstantiator> {
|
||||
class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs;
|
||||
SourceLocation Loc;
|
||||
DeclarationName Entity;
|
||||
|
@ -604,13 +603,9 @@ namespace {
|
|||
Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
|
||||
NonTypeTemplateParmDecl *D);
|
||||
|
||||
/// \brief Transforms a function proto type by performing
|
||||
/// substitution in the function parameters, possibly adjusting
|
||||
/// their types and marking default arguments as uninstantiated.
|
||||
bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
|
||||
llvm::SmallVectorImpl<QualType> &PTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
|
||||
|
||||
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||
FunctionProtoTypeLoc TL,
|
||||
QualType ObjectType);
|
||||
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm);
|
||||
|
||||
/// \brief Transforms a template type parameter type by performing
|
||||
|
@ -825,23 +820,12 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
|
|||
E->getParam());
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
|
||||
llvm::SmallVectorImpl<QualType> &PTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
|
||||
// Create a local instantiation scope for the parameters.
|
||||
// FIXME: When we implement the C++0x late-specified return type,
|
||||
// we will need to move this scope out to the function type itself.
|
||||
bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0);
|
||||
Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope,
|
||||
IsTemporaryScope);
|
||||
|
||||
if (TreeTransform<TemplateInstantiator>::
|
||||
TransformFunctionTypeParams(TL, PTypes, PVars))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||
FunctionProtoTypeLoc TL,
|
||||
QualType ObjectType) {
|
||||
// We need a local instantiation scope for this function prototype.
|
||||
Sema::LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
|
||||
return inherited::TransformFunctionProtoType(TLB, TL, ObjectType);
|
||||
}
|
||||
|
||||
ParmVarDecl *
|
||||
|
@ -1600,3 +1584,29 @@ bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output,
|
|||
|
||||
return Instantiator.TransformTemplateArgument(Input, Output);
|
||||
}
|
||||
|
||||
Decl *Sema::LocalInstantiationScope::getInstantiationOf(const Decl *D) {
|
||||
for (LocalInstantiationScope *Current = this; Current;
|
||||
Current = Current->Outer) {
|
||||
// Check if we found something within this scope.
|
||||
llvm::DenseMap<const Decl *, Decl *>::iterator Found
|
||||
= Current->LocalDecls.find(D);
|
||||
if (Found != Current->LocalDecls.end())
|
||||
return Found->second;
|
||||
|
||||
// If we aren't combined with our outer scope, we're done.
|
||||
if (!Current->CombineWithOuterScope)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(D->isInvalidDecl() &&
|
||||
"declaration was not instantiated in this scope!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sema::LocalInstantiationScope::InstantiatedLocal(const Decl *D,
|
||||
Decl *Inst) {
|
||||
Decl *&Stored = LocalDecls[D];
|
||||
assert((!Stored || Stored == Inst)&& "Already instantiated this local");
|
||||
Stored = Inst;
|
||||
}
|
||||
|
|
|
@ -822,7 +822,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
|
|||
// merged with the local instantiation scope for the function template
|
||||
// itself.
|
||||
Sema::LocalInstantiationScope Scope(SemaRef);
|
||||
|
||||
|
||||
TemplateParameterList *TempParams = D->getTemplateParameters();
|
||||
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
|
||||
if (!InstParams)
|
||||
|
@ -1775,11 +1775,18 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
|
|||
|
||||
if (NewTInfo != OldTInfo) {
|
||||
// Get parameters from the new type info.
|
||||
TypeLoc OldTL = OldTInfo->getTypeLoc();
|
||||
FunctionProtoTypeLoc *OldProtoLoc = cast<FunctionProtoTypeLoc>(&OldTL);
|
||||
TypeLoc NewTL = NewTInfo->getTypeLoc();
|
||||
FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
|
||||
assert(NewProtoLoc && "Missing prototype?");
|
||||
for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
|
||||
for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) {
|
||||
// FIXME: Variadic templates will break this.
|
||||
Params.push_back(NewProtoLoc->getArg(i));
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
|
||||
OldProtoLoc->getArg(i),
|
||||
NewProtoLoc->getArg(i));
|
||||
}
|
||||
} else {
|
||||
// The function type itself was not dependent and therefore no
|
||||
// substitution occurred. However, we still need to instantiate
|
||||
|
|
|
@ -2907,17 +2907,19 @@ QualType
|
|||
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||
FunctionProtoTypeLoc TL,
|
||||
QualType ObjectType) {
|
||||
FunctionProtoType *T = TL.getTypePtr();
|
||||
QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
|
||||
if (ResultType.isNull())
|
||||
return QualType();
|
||||
|
||||
// Transform the parameters.
|
||||
// Transform the parameters. We do this first for the benefit of template
|
||||
// instantiations, so that the ParmVarDecls get/ placed into the template
|
||||
// instantiation scope before we transform the function type.
|
||||
llvm::SmallVector<QualType, 4> ParamTypes;
|
||||
llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
|
||||
if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls))
|
||||
return QualType();
|
||||
|
||||
|
||||
FunctionProtoType *T = TL.getTypePtr();
|
||||
QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
|
||||
if (ResultType.isNull())
|
||||
return QualType();
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() ||
|
||||
ResultType != T->getResultType() ||
|
||||
|
|
|
@ -53,3 +53,26 @@ void use_func_ptr() {
|
|||
};
|
||||
|
||||
template void use_func_ptr<int, float, double>();
|
||||
|
||||
namespace PR6990 {
|
||||
template < typename , typename = int, typename = int > struct X1;
|
||||
template <typename >
|
||||
struct X2;
|
||||
|
||||
template <typename = int *, typename TokenT = int,
|
||||
typename = int( X2<TokenT> &)>
|
||||
struct X3
|
||||
{
|
||||
};
|
||||
|
||||
template <typename , typename P>
|
||||
struct X3_base : X3< X1<int, P> >
|
||||
{
|
||||
protected: typedef X1< P> type;
|
||||
X3<type> e;
|
||||
};
|
||||
|
||||
struct r : X3_base<int, int>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue