When a pack expansion occurs in the template argument list of an alias
template without a corresponding parameter pack, don't immediately substitute the alias template. This is under discussion in the C++ committee, and may become ill-formed, but for now we match GCC. llvm-svn: 149697
This commit is contained in:
parent
e340deedbf
commit
1f79ca839c
|
@ -3484,8 +3484,12 @@ class TemplateSpecializationType
|
|||
|
||||
/// \brief - The number of template arguments named in this class
|
||||
/// template specialization.
|
||||
unsigned NumArgs;
|
||||
unsigned NumArgs : 31;
|
||||
|
||||
/// \brief Whether this template specialization type is a substituted
|
||||
/// type alias.
|
||||
bool TypeAlias : 1;
|
||||
|
||||
TemplateSpecializationType(TemplateName T,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs, QualType Canon,
|
||||
|
@ -3527,9 +3531,23 @@ public:
|
|||
return isa<InjectedClassNameType>(getCanonicalTypeInternal());
|
||||
}
|
||||
|
||||
/// True if this template specialization type is for a type alias
|
||||
/// template.
|
||||
bool isTypeAlias() const;
|
||||
/// \brief Determine if this template specialization type is for a type alias
|
||||
/// template that has been substituted.
|
||||
///
|
||||
/// Nearly every template specialization type whose template is an alias
|
||||
/// template will be substituted. However, this is not the case when
|
||||
/// the specialization contains a pack expansion but the template alias
|
||||
/// does not have a corresponding parameter pack, e.g.,
|
||||
///
|
||||
/// \code
|
||||
/// template<typename T, typename U, typename V> struct S;
|
||||
/// template<typename T, typename U> using A = S<T, int, U>;
|
||||
/// template<typename... Ts> struct X {
|
||||
/// typedef A<Ts...> type; // not a type alias
|
||||
/// };
|
||||
/// \endcode
|
||||
bool isTypeAlias() const { return TypeAlias; }
|
||||
|
||||
/// Get the aliased type, if this is a specialization of a type alias
|
||||
/// template.
|
||||
QualType getAliasedType() const {
|
||||
|
|
|
@ -4133,12 +4133,18 @@ public:
|
|||
/// \param Converted Will receive the converted, canonicalized template
|
||||
/// arguments.
|
||||
///
|
||||
///
|
||||
/// \param ExpansionIntoFixedList If non-NULL, will be set true to indicate
|
||||
/// when the template arguments contain a pack expansion that is being
|
||||
/// expanded into a fixed parameter list.
|
||||
///
|
||||
/// \returns True if an error occurred, false otherwise.
|
||||
bool CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
TemplateArgumentListInfo &TemplateArgs,
|
||||
bool PartialTemplateArgs,
|
||||
SmallVectorImpl<TemplateArgument> &Converted);
|
||||
SmallVectorImpl<TemplateArgument> &Converted,
|
||||
bool *ExpansionIntoFixedList = 0);
|
||||
|
||||
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
|
||||
const TemplateArgumentLoc &Arg,
|
||||
|
|
|
@ -2450,6 +2450,17 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
|
|||
Underlying);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static bool hasAnyPackExpansions(const TemplateArgument *Args,
|
||||
unsigned NumArgs) {
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
if (Args[I].isPackExpansion())
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
QualType
|
||||
ASTContext::getTemplateSpecializationType(TemplateName Template,
|
||||
const TemplateArgument *Args,
|
||||
|
@ -2461,16 +2472,18 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
|
|||
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
|
||||
Template = TemplateName(QTN->getTemplateDecl());
|
||||
|
||||
bool isTypeAlias =
|
||||
bool IsTypeAlias =
|
||||
Template.getAsTemplateDecl() &&
|
||||
isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
|
||||
|
||||
QualType CanonType;
|
||||
if (!Underlying.isNull())
|
||||
CanonType = getCanonicalType(Underlying);
|
||||
else {
|
||||
assert(!isTypeAlias &&
|
||||
"Underlying type for template alias must be computed by caller");
|
||||
// We can get here with an alias template when the specialization contains
|
||||
// a pack expansion that does not match up with a parameter pack.
|
||||
assert((!IsTypeAlias || hasAnyPackExpansions(Args, NumArgs)) &&
|
||||
"Caller must compute aliased type");
|
||||
IsTypeAlias = false;
|
||||
CanonType = getCanonicalTemplateSpecializationType(Template, Args,
|
||||
NumArgs);
|
||||
}
|
||||
|
@ -2480,13 +2493,11 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
|
|||
// we don't unique and don't want to lose.
|
||||
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * NumArgs +
|
||||
(isTypeAlias ? sizeof(QualType) : 0),
|
||||
(IsTypeAlias? sizeof(QualType) : 0),
|
||||
TypeAlignment);
|
||||
TemplateSpecializationType *Spec
|
||||
= new (Mem) TemplateSpecializationType(Template,
|
||||
Args, NumArgs,
|
||||
CanonType,
|
||||
isTypeAlias ? Underlying : QualType());
|
||||
= new (Mem) TemplateSpecializationType(Template, Args, NumArgs, CanonType,
|
||||
IsTypeAlias ? Underlying : QualType());
|
||||
|
||||
Types.push_back(Spec);
|
||||
return QualType(Spec, 0);
|
||||
|
@ -2498,9 +2509,6 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
|
|||
unsigned NumArgs) const {
|
||||
assert(!Template.getAsDependentTemplateName() &&
|
||||
"No dependent template names here!");
|
||||
assert((!Template.getAsTemplateDecl() ||
|
||||
!isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
|
||||
"Underlying type for template alias must be computed by caller");
|
||||
|
||||
// Look through qualified template names.
|
||||
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
|
||||
|
|
|
@ -1884,7 +1884,7 @@ TemplateSpecializationType(TemplateName T,
|
|||
false,
|
||||
Canon.isNull()? T.containsUnexpandedParameterPack()
|
||||
: Canon->containsUnexpandedParameterPack()),
|
||||
Template(T), NumArgs(NumArgs) {
|
||||
Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
|
||||
assert(!T.getAsDependentTemplateName() &&
|
||||
"Use DependentTemplateSpecializationType for dependent template-name");
|
||||
assert((T.getKind() == TemplateName::Template ||
|
||||
|
@ -1923,10 +1923,7 @@ TemplateSpecializationType(TemplateName T,
|
|||
}
|
||||
|
||||
// Store the aliased type if this is a type alias template specialization.
|
||||
bool IsTypeAlias = !AliasedType.isNull();
|
||||
assert(IsTypeAlias == isTypeAlias() &&
|
||||
"allocated wrong size for type alias");
|
||||
if (IsTypeAlias) {
|
||||
if (TypeAlias) {
|
||||
TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
|
||||
*reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
|
||||
}
|
||||
|
@ -1943,11 +1940,6 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
|||
Args[Idx].Profile(ID, Context);
|
||||
}
|
||||
|
||||
bool TemplateSpecializationType::isTypeAlias() const {
|
||||
TemplateDecl *D = Template.getAsTemplateDecl();
|
||||
return D && isa<TypeAliasTemplateDecl>(D);
|
||||
}
|
||||
|
||||
QualType
|
||||
QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
|
||||
if (!hasNonFastQualifiers())
|
||||
|
|
|
@ -1918,15 +1918,17 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
|||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
SmallVector<TemplateArgument, 4> Converted;
|
||||
bool ExpansionIntoFixedList = false;
|
||||
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
|
||||
false, Converted))
|
||||
false, Converted, &ExpansionIntoFixedList))
|
||||
return QualType();
|
||||
|
||||
QualType CanonType;
|
||||
|
||||
bool InstantiationDependent = false;
|
||||
if (TypeAliasTemplateDecl *AliasTemplate
|
||||
= dyn_cast<TypeAliasTemplateDecl>(Template)) {
|
||||
TypeAliasTemplateDecl *AliasTemplate = 0;
|
||||
if (!ExpansionIntoFixedList &&
|
||||
(AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template))) {
|
||||
// Find the canonical type for this type alias template specialization.
|
||||
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
|
||||
if (Pattern->isInvalidDecl())
|
||||
|
@ -2891,7 +2893,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
SourceLocation TemplateLoc,
|
||||
TemplateArgumentListInfo &TemplateArgs,
|
||||
bool PartialTemplateArgs,
|
||||
SmallVectorImpl<TemplateArgument> &Converted) {
|
||||
SmallVectorImpl<TemplateArgument> &Converted,
|
||||
bool *ExpansionIntoFixedList) {
|
||||
if (ExpansionIntoFixedList)
|
||||
*ExpansionIntoFixedList = false;
|
||||
|
||||
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||
unsigned NumParams = Params->size();
|
||||
unsigned NumArgs = TemplateArgs.size();
|
||||
|
@ -2901,7 +2907,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
|
||||
bool HasParameterPack =
|
||||
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
|
||||
|
||||
|
||||
// C++ [temp.arg]p1:
|
||||
// [...] The type and form of each template-argument specified in
|
||||
// a template-id shall match the type and form specified for the
|
||||
|
@ -3088,6 +3094,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
ArgumentPack.size()));
|
||||
ArgumentPack.clear();
|
||||
}
|
||||
} else if (ExpansionIntoFixedList) {
|
||||
// We have expanded a pack into a fixed list.
|
||||
*ExpansionIntoFixedList = true;
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
|
|
|
@ -118,3 +118,10 @@ namespace PartialSpecialization {
|
|||
X0<int, float> x0if;
|
||||
X0<int, float, double> x0ifd;
|
||||
}
|
||||
|
||||
namespace FixedAliasTemplate {
|
||||
template<typename,typename,typename> struct S {};
|
||||
template<typename T, typename U> using U = S<T, int, U>;
|
||||
template<typename...Ts> U<Ts...> &f(U<Ts...>, Ts...);
|
||||
S<int, int, double> &s1 = f({}, 0, 0.0);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@ template<typename T> void g(T);
|
|||
|
||||
template<template<typename> class F> void h(F<int>);
|
||||
|
||||
template<typename,typename,typename> struct S {};
|
||||
template<typename T, typename U> using U = S<T, int, U>;
|
||||
template<typename...Ts> void h(U<Ts...>, Ts...);
|
||||
|
||||
// CHECK: define void @_Z1zv(
|
||||
void z() {
|
||||
vector<int> VI;
|
||||
|
@ -38,4 +42,7 @@ void z() {
|
|||
Vec<Vec<int>> VVI;
|
||||
g(VVI);
|
||||
// CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
|
||||
|
||||
// CHECK: call void @_Z1hIJidEEv1UIDpT_ES2_
|
||||
h({}, 0, 0.0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue