Implement transformation of template names within the generic tree

transform, then use the result for template instantiation. The generic
transformation fixes a few issues:

  - It copes better with template template parameters and member
  templates (when they're implemented). 
  - The logic used to replace template template parameters with their
  arguments is now centralized in TransformDecl, so that it will apply
  for other declaration-instantiation steps.
  - The error-recovery strategy is normalized now, so that any error
  results in a NULL TemplateName.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78292 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-08-06 06:41:21 +00:00
Родитель 38b02b912e
Коммит d1067e5a0a
3 изменённых файлов: 182 добавлений и 72 удалений

Просмотреть файл

@ -324,9 +324,6 @@ namespace {
/// this declaration.
Decl *TransformDecl(Decl *D);
/// \brief Transform the given template name by instantiating it.
TemplateName TransformTemplateName(TemplateName Template);
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T);
@ -338,15 +335,22 @@ Sema::OwningExprResult TemplateInstantiator::TransformExpr(Expr *E) {
}
Decl *TemplateInstantiator::TransformDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(D)) {
// FIXME: Depth reduction
assert(TTP->getDepth() == 0 &&
"Cannot reduce depth of a template template parameter");
assert(TemplateArgs[TTP->getPosition()].getAsDecl() &&
"Wrong kind of template template argument");
TemplateDecl *Template
= dyn_cast<TemplateDecl>(TemplateArgs[TTP->getPosition()].getAsDecl());
assert(Template && "Expected a template");
return Template;
}
return SemaRef.InstantiateCurrentDeclRef(cast_or_null<NamedDecl>(D));
}
TemplateName
TemplateInstantiator::TransformTemplateName(TemplateName Template) {
return getSema().InstantiateTemplateName(Template, /*FIXME*/Loc,
TemplateArgs);
}
QualType
TemplateInstantiator::TransformTemplateTypeParmType(
const TemplateTypeParmType *T) {
@ -720,66 +724,9 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
TemplateName
Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(
Name.getAsTemplateDecl())) {
assert(TTP->getDepth() == 0 &&
"Cannot reduce depth of a template template parameter");
assert(TemplateArgs[TTP->getPosition()].getAsDecl() &&
"Wrong kind of template template argument");
ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(
TemplateArgs[TTP->getPosition()].getAsDecl());
assert(ClassTemplate && "Expected a class template");
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
NestedNameSpecifier *NNS
= InstantiateNestedNameSpecifier(QTN->getQualifier(),
/*FIXME=*/SourceRange(Loc),
TemplateArgs);
if (NNS)
return Context.getQualifiedTemplateName(NNS,
QTN->hasTemplateKeyword(),
ClassTemplate);
}
return TemplateName(ClassTemplate);
} else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
NestedNameSpecifier *NNS
= InstantiateNestedNameSpecifier(DTN->getQualifier(),
/*FIXME=*/SourceRange(Loc),
TemplateArgs);
if (!NNS) // FIXME: Not the best recovery strategy.
return Name;
if (NNS->isDependent())
return Context.getDependentTemplateName(NNS, DTN->getName());
// Somewhat redundant with ActOnDependentTemplateName.
CXXScopeSpec SS;
SS.setRange(SourceRange(Loc));
SS.setScopeRep(NNS);
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS);
if (TNK == TNK_Non_template) {
Diag(Loc, diag::err_template_kw_refers_to_non_template)
<< DTN->getName();
return Name;
} else if (TNK == TNK_Function_template) {
Diag(Loc, diag::err_template_kw_refers_to_non_template)
<< DTN->getName();
return Name;
}
return Template.getAsVal<TemplateName>();
}
// FIXME: Even if we're referring to a Decl that isn't a template template
// parameter, we may need to instantiate the outer contexts of that
// Decl. However, this won't be needed until we implement member templates.
return Name;
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
DeclarationName());
return Instantiator.TransformTemplateName(Name);
}
TemplateArgument Sema::Instantiate(TemplateArgument Arg,

Просмотреть файл

@ -171,8 +171,10 @@ public:
/// \brief Transform the given template name.
///
/// FIXME: At the moment, subclasses must override this.
TemplateName TransformTemplateName(TemplateName Template);
/// By default, transforms the template name by transforming the declarations
/// and nested-name-specifiers that occur within the template name.
/// Subclasses may override this function to provide alternate behavior.
TemplateName TransformTemplateName(TemplateName Name);
/// \brief Transform the given template argument.
///
@ -433,6 +435,36 @@ public:
SourceRange Range,
bool TemplateKW,
QualType T);
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
///
/// By default, builds the new template name directly. Subclasses may override
/// this routine to provide different behavior.
TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
bool TemplateKW,
TemplateDecl *Template);
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and a set of
/// overloaded function templates.
///
/// By default, builds the new template name directly. Subclasses may override
/// this routine to provide different behavior.
TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
bool TemplateKW,
OverloadedFunctionDecl *Ovl);
/// \brief Build a new template name given a nested name specifier and the
/// name that is referred to as a template.
///
/// By default, performs semantic analysis to determine whether the name can
/// be resolved to a specific template, then builds the appropriate kind of
/// template name. Subclasses may override this routine to provide different
/// behavior.
TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo &II);
};
template<typename Derived>
@ -477,6 +509,9 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::TypeSpec: {
QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
if (T.isNull())
return 0;
if (!getDerived().AlwaysRebuild() &&
Prefix == NNS->getPrefix() &&
T == QualType(NNS->getAsType(), 0))
@ -492,6 +527,88 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
return 0;
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::TransformTemplateName(TemplateName Name) {
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
/*FIXME:*/SourceRange(getDerived().getBaseLocation()));
if (!NNS)
return TemplateName();
if (TemplateDecl *Template = QTN->getTemplateDecl()) {
TemplateDecl *TransTemplate
= cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
if (!TransTemplate)
return TemplateName();
if (!getDerived().AlwaysRebuild() &&
NNS == QTN->getQualifier() &&
TransTemplate == Template)
return Name;
return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
TransTemplate);
}
OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl();
assert(Ovl && "Not a template name or an overload set?");
OverloadedFunctionDecl *TransOvl
= cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
if (!TransOvl)
return TemplateName();
if (!getDerived().AlwaysRebuild() &&
NNS == QTN->getQualifier() &&
TransOvl == Ovl)
return Name;
return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
TransOvl);
}
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
/*FIXME:*/SourceRange(getDerived().getBaseLocation()));
if (!NNS)
return TemplateName();
if (!getDerived().AlwaysRebuild() &&
NNS == DTN->getQualifier())
return Name;
return getDerived().RebuildTemplateName(NNS, *DTN->getName());
}
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
TemplateDecl *TransTemplate
= cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template));
if (!TransTemplate)
return TemplateName();
if (!getDerived().AlwaysRebuild() &&
TransTemplate == Template)
return Name;
return TemplateName(TransTemplate);
}
OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl();
assert(Ovl && "Not a template name or an overload set?");
OverloadedFunctionDecl *TransOvl
= cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl));
if (!TransOvl)
return TemplateName();
if (!getDerived().AlwaysRebuild() &&
TransOvl == Ovl)
return Name;
return TemplateName(TransOvl);
}
template<typename Derived>
TemplateArgument
TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) {
@ -1343,6 +1460,51 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
return 0;
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
bool TemplateKW,
TemplateDecl *Template) {
return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW,
Template);
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
bool TemplateKW,
OverloadedFunctionDecl *Ovl) {
return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl);
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo &II) {
if (Qualifier->isDependent())
return SemaRef.Context.getDependentTemplateName(Qualifier, &II);
// Somewhat redundant with ActOnDependentTemplateName.
CXXScopeSpec SS;
SS.setRange(SourceRange(getDerived().getBaseLocation()));
SS.setScopeRep(Qualifier);
Sema::TemplateTy Template;
TemplateNameKind TNK = SemaRef.isTemplateName(II, 0, Template, &SS);
if (TNK == TNK_Non_template) {
SemaRef.Diag(getDerived().getBaseLocation(),
diag::err_template_kw_refers_to_non_template)
<< &II;
return TemplateName();
} else if (TNK == TNK_Function_template) {
SemaRef.Diag(getDerived().getBaseLocation(),
diag::err_template_kw_refers_to_non_template)
<< &II;
return TemplateName();
}
return Template.getAsVal<TemplateName>();
}
} // end namespace clang
#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H

Просмотреть файл

@ -35,7 +35,8 @@ void test() {
apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \
// FIXME: expected-error{{unexpected type name 'type': expected expression}}
apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}}
apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} \
// FIXME: expected-error{{unexpected type name 'type': expected expression}}
}