Improve instantiation of default template arguments for nested

templates. The instantiation of these default arguments must be (and
now, is) delayed until the template argument is actually used, at
which point we substitute all levels of template arguments
concurrently.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86578 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-11-09 19:17:50 +00:00
Родитель 62cf322cf1
Коммит 0f8716b7bb
5 изменённых файлов: 175 добавлений и 45 удалений

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

@ -2844,7 +2844,8 @@ public:
// C++ Template Instantiation
//
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost = 0);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {

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

@ -1449,6 +1449,102 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return false;
}
/// \brief Substitute template arguments into the default template argument for
/// the given template type parameter.
///
/// \param SemaRef the semantic analysis object for which we are performing
/// the substitution.
///
/// \param Template the template that we are synthesizing template arguments
/// for.
///
/// \param TemplateLoc the location of the template name that started the
/// template-id we are checking.
///
/// \param RAngleLoc the location of the right angle bracket ('>') that
/// terminates the template-id.
///
/// \param Param the template template parameter whose default we are
/// substituting into.
///
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
static DeclaratorInfo *
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTypeParmDecl *Param,
TemplateArgumentListBuilder &Converted) {
DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isDependentType()) {
TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
/*TakeArgs=*/false);
MultiLevelTemplateArgumentList AllTemplateArgs
= SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
Param->getDefaultArgumentLoc(),
Param->getDeclName());
}
return ArgType;
}
/// \brief Substitute template arguments into the default template argument for
/// the given non-type template parameter.
///
/// \param SemaRef the semantic analysis object for which we are performing
/// the substitution.
///
/// \param Template the template that we are synthesizing template arguments
/// for.
///
/// \param TemplateLoc the location of the template name that started the
/// template-id we are checking.
///
/// \param RAngleLoc the location of the right angle bracket ('>') that
/// terminates the template-id.
///
/// \param Param the template template parameter whose default we are
/// substituting into.
///
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
static Sema::OwningExprResult
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
NonTypeTemplateParmDecl *Param,
TemplateArgumentListBuilder &Converted) {
TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
/*TakeArgs=*/false);
MultiLevelTemplateArgumentList AllTemplateArgs
= SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs);
}
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@ -1516,44 +1612,27 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!TTP->hasDefaultArgument())
break;
DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isDependentType()) {
InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
ArgType = SubstType(ArgType,
MultiLevelTemplateArgumentList(TemplateArgs),
TTP->getDefaultArgumentLoc(),
TTP->getDeclName());
}
DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
Template,
TemplateLoc,
RAngleLoc,
TTP,
Converted);
if (!ArgType)
return true;
Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType);
Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
Sema::OwningExprResult E
= SubstExpr(NTTP->getDefaultArgument(),
MultiLevelTemplateArgumentList(TemplateArgs));
Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
NTTP,
Converted);
if (E.isInvalid())
return true;

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

@ -28,11 +28,20 @@ using namespace clang;
/// \brief Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
/// \param D the declaration for which we are computing template instantiation
/// arguments.
///
/// \param Innermost if non-NULL, the innermost template argument list.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
Sema::getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
if (Innermost)
Result.addOuterTemplateArguments(Innermost);
DeclContext *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx)
Ctx = D->getDeclContext();

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

@ -923,18 +923,8 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->wasDeclaredWithTypename(),
D->isParameterPack());
// FIXME: Do we actually want to perform substitution here? I don't think
// we do.
if (D->hasDefaultArgument()) {
DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo();
DeclaratorInfo *DefaultInst
= SemaRef.SubstType(DefaultPattern, TemplateArgs,
D->getDefaultArgumentLoc(),
D->getDeclName());
Inst->setDefaultArgument(DefaultInst,
D->defaultArgumentWasInherited() /* preserve? */);
}
if (D->hasDefaultArgument())
Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
// Introduce this template parameter's instantiation into the instantiation
// scope.

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

@ -42,3 +42,54 @@ template<>
struct B<void> {
typedef B<void*> type;
};
// Nested default arguments for template parameters.
template<typename T> struct X1 { };
template<typename T>
struct X2 {
template<typename U = typename X1<T>::type> // expected-error{{no type named}}
struct Inner1 { };
template<T Value = X1<T>::value> // expected-error{{no member named 'value'}}
struct NonType1 { };
template<T Value>
struct Inner2 { };
template<typename U>
struct Inner3 {
template<typename X = T, typename V = U>
struct VeryInner { };
template<T Value1 = sizeof(T), T Value2 = sizeof(U),
T Value3 = Value1 + Value2>
struct NonType2 { };
};
};
X2<int> x2i;
X2<int>::Inner1<float> x2iif;
X2<int>::Inner1<> x2bad; // expected-note{{instantiation of default argument}}
X2<int>::NonType1<'a'> x2_nontype1;
X2<int>::NonType1<> x2_nontype1_bad; // expected-note{{instantiation of default argument}}
// Check multi-level substitution into template type arguments
X2<int>::Inner3<float>::VeryInner<> vi;
X2<char>::Inner3<int>::NonType2<> x2_deep_nontype;
template<typename T, typename U>
struct is_same { static const bool value = false; };
template<typename T>
struct is_same<T, T> { static const bool value = true; };
static int array1[is_same<__typeof__(vi),
X2<int>::Inner3<float>::VeryInner<int, float> >::value? 1 : -1];
static int array2[is_same<__typeof(x2_deep_nontype),
X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int),
sizeof(char)+sizeof(int)> >::value? 1 : -1];