Start implementing support for substitution into pack expansions that

involve template parameter packs at multiple template levels that
occur within the signatures members of class templates (and partial
specializations thereof). This is a work-in-progress that is deficient
in several ways, notably:
  - It only works for template type parameter packs, but we need to
  also support non-type template parameter packs and template template
  parameter packs.
  - It doesn't keep track of the lengths of the substituted argument
  packs in the expansion, so it can't properly diagnose length
  mismatches.

However, this is a concrete step in the right direction.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123425 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-01-14 02:55:32 +00:00
Родитель 4e26caa036
Коммит c3069d618f
18 изменённых файлов: 254 добавлений и 5 удалений

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

@ -102,6 +102,8 @@ class ASTContext {
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
SubstTemplateTypeParmTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
SubstTemplateTypeParmPackTypes;
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
TemplateSpecializationTypes;
mutable llvm::FoldingSet<ParenType> ParenTypes;
@ -664,6 +666,9 @@ public:
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
QualType Replacement) const;
QualType getSubstTemplateTypeParmPackType(
const TemplateTypeParmType *Replaced,
const TemplateArgument &ArgPack);
QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,

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

@ -718,6 +718,7 @@ DEF_TRAVERSE_TYPE(RecordType, { })
DEF_TRAVERSE_TYPE(EnumType, { })
DEF_TRAVERSE_TYPE(TemplateTypeParmType, { })
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { })
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { })
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName()));
@ -925,6 +926,7 @@ DEF_TRAVERSE_TYPELOC(RecordType, { })
DEF_TRAVERSE_TYPELOC(EnumType, { })
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { })
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { })
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { })
// FIXME: use the loc for the template name?
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {

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

@ -2860,6 +2860,59 @@ public:
static bool classof(const SubstTemplateTypeParmType *T) { return true; }
};
/// \brief Represents the result of substituting a set of types for a template
/// type parameter pack.
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
/// parameter lists, this type node is used to represent a template type
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
/// that pack expansion (e.g., when all template parameters have corresponding
/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
/// at the current pack substitution index.
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// \brief The original type parameter.
const TemplateTypeParmType *Replaced;
/// \brief A pointer to the set of template arguments that this
/// parameter pack is instantiated with.
const TemplateArgument *Arguments;
/// \brief The number of template arguments in \c Arguments.
unsigned NumArguments;
SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
const TemplateArgument &ArgPack);
friend class ASTContext;
public:
IdentifierInfo *getName() const { return Replaced->getName(); }
/// Gets the template parameter that was substituted for.
const TemplateTypeParmType *getReplacedParameter() const {
return Replaced;
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
TemplateArgument getArgumentPack() const;
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
const TemplateTypeParmType *Replaced,
const TemplateArgument &ArgPack);
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParmPack;
}
static bool classof(const SubstTemplateTypeParmPackType *T) { return true; }
};
/// \brief Represents the type of a template specialization as written
/// in the source code.
///

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

@ -592,6 +592,13 @@ class SubstTemplateTypeParmTypeLoc :
SubstTemplateTypeParmType> {
};
/// \brief Wrapper for substituted template type parameters.
class SubstTemplateTypeParmPackTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
SubstTemplateTypeParmPackTypeLoc,
SubstTemplateTypeParmPackType> {
};
struct AttributedLocInfo {
union {
Expr *ExprOperand;

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

@ -91,6 +91,7 @@ NON_CANONICAL_TYPE(Elaborated, Type)
NON_CANONICAL_TYPE(Attributed, Type)
DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)

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

@ -555,7 +555,9 @@ namespace clang {
/// \brief A PackExpansionType record.
TYPE_PACK_EXPANSION = 35,
/// \brief An AttributedType record.
TYPE_ATTRIBUTED = 36
TYPE_ATTRIBUTED = 36,
/// \brief A SubstTemplateTypeParmPackType record.
TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37
};
/// \brief The type IDs for special types constructed by semantic

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

@ -1932,6 +1932,42 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
return QualType(SubstParm, 0);
}
/// \brief Retrieve a
QualType ASTContext::getSubstTemplateTypeParmPackType(
const TemplateTypeParmType *Parm,
const TemplateArgument &ArgPack) {
#ifndef NDEBUG
for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
PEnd = ArgPack.pack_end();
P != PEnd; ++P) {
assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type");
assert(P->getAsType().isCanonical() && "Pack contains non-canonical type");
}
#endif
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
void *InsertPos = 0;
if (SubstTemplateTypeParmPackType *SubstParm
= SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(SubstParm, 0);
QualType Canon;
if (!Parm->isCanonicalUnqualified()) {
Canon = getCanonicalType(QualType(Parm, 0));
Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon),
ArgPack);
SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
}
SubstTemplateTypeParmPackType *SubstParm
= new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
ArgPack);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
return QualType(SubstParm, 0);
}
/// \brief Retrieve the template type parameter type for a template
/// parameter or parameter pack with the given depth, index, and (optionally)
/// name.

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

@ -1383,6 +1383,11 @@ void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
mangleTemplateParameter(T->getIndex());
}
// <type> ::= <template-param>
void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
mangleTemplateParameter(T->getReplacedParameter()->getIndex());
}
// <type> ::= P <type> # pointer-to
void CXXNameMangler::mangleType(const PointerType *T) {
Out << 'P';

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

@ -1011,6 +1011,12 @@ void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) {
assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!");
}
void MicrosoftCXXNameMangler::mangleType(
const SubstTemplateTypeParmPackType *T) {
assert(false &&
"Don't know how to mangle SubstTemplateTypeParmPackTypes yet!");
}
// <type> ::= <pointer-type>
// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
void MicrosoftCXXNameMangler::mangleType(const PointerType *T) {

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

@ -1244,6 +1244,34 @@ bool EnumType::classof(const TagType *TT) {
return isa<EnumDecl>(TT->getDecl());
}
SubstTemplateTypeParmPackType::
SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
const TemplateArgument &ArgPack)
: Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param),
Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size())
{
}
TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
return TemplateArgument(Arguments, NumArguments);
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getReplacedParameter(), getArgumentPack());
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
const TemplateTypeParmType *Replaced,
const TemplateArgument &ArgPack) {
ID.AddPointer(Replaced);
ID.AddInteger(ArgPack.pack_size());
for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
PEnd = ArgPack.pack_end();
P != PEnd; ++P)
ID.AddPointer(P->getAsType().getAsOpaquePtr());
}
bool TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) {
return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size());

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

@ -568,6 +568,12 @@ void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
print(T->getReplacementType(), S);
}
void TypePrinter::printSubstTemplateTypeParmPack(
const SubstTemplateTypeParmPackType *T,
std::string &S) {
printTemplateTypeParm(T->getReplacedParameter(), S);
}
void TypePrinter::printTemplateSpecialization(
const TemplateSpecializationType *T,
std::string &S) {

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

@ -2713,6 +2713,11 @@ bool UnnamedLocalNoLinkageFinder::VisitTemplateTypeParmType(
return false;
}
bool UnnamedLocalNoLinkageFinder::VisitSubstTemplateTypeParmPackType(
const SubstTemplateTypeParmPackType *) {
return false;
}
bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType(
const TemplateSpecializationType*) {
return false;

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

@ -712,6 +712,12 @@ namespace {
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL);
/// \brief Transforms an already-substituted template type parameter pack
/// into either itself (if we aren't substituting into its pack expansion)
/// or the appropriate substituted argument.
QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
SubstTemplateTypeParmPackTypeLoc TL);
ExprResult TransformCallExpr(CallExpr *CE) {
getSema().CallsUndergoingInstantiation.push_back(CE);
ExprResult Result =
@ -1024,10 +1030,15 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
"Missing argument pack");
if (getSema().ArgumentPackSubstitutionIndex == -1) {
// FIXME: Variadic templates fun case.
getSema().Diag(TL.getSourceRange().getBegin(),
diag::err_pack_expansion_mismatch_unsupported);
return QualType();
// We have the template argument pack, but we're not expanding the
// enclosing pack expansion yet. Just save the template argument
// pack for later substitution.
QualType Result
= getSema().Context.getSubstTemplateTypeParmPackType(T, Arg);
SubstTemplateTypeParmPackTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
@ -1063,6 +1074,32 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
QualType
TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmPackTypeLoc TL) {
if (getSema().ArgumentPackSubstitutionIndex == -1) {
// We aren't expanding the parameter pack, so just return ourselves.
SubstTemplateTypeParmPackTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType());
NewTL.setNameLoc(TL.getNameLoc());
return TL.getType();
}
const TemplateArgument &ArgPack = TL.getTypePtr()->getArgumentPack();
unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex;
assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
QualType Result = ArgPack.pack_begin()[Index].getAsType();
Result = getSema().Context.getSubstTemplateTypeParmType(
TL.getTypePtr()->getReplacedParameter(),
Result);
SubstTemplateTypeParmTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
/// \brief Perform substitution on the type T with a given set of template
/// arguments.
///

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

@ -456,6 +456,10 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
// FIXME: Variadic templates. Even if we don't expand, we'd still like to
// return the number of expansions back to the caller, perhaps as an
// llvm::Optional, so that it can be embedded in the pack expansion. This
// is important for the multi-level substitution case.
for (unsigned I = 0; I != NumUnexpanded; ++I) {
// Compute the depth and index for this parameter pack.
unsigned Depth;

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

@ -3926,6 +3926,13 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
return TransformTypeSpecType(TLB, TL);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmPackTypeLoc TL) {
return TransformTypeSpecType(TLB, TL);
}
template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TypeLocBuilder &TLB,

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

@ -2997,6 +2997,15 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Replacement);
}
case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
unsigned Idx = 0;
QualType Parm = GetType(Record[Idx++]);
TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
return Context->getSubstTemplateTypeParmPackType(
cast<TemplateTypeParmType>(Parm),
ArgPack);
}
case TYPE_INJECTED_CLASS_NAME: {
CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0]));
QualType TST = GetType(Record[1]); // probably derivable
@ -3233,6 +3242,10 @@ void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
SubstTemplateTypeParmTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
SubstTemplateTypeParmPackTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));

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

@ -243,6 +243,14 @@ ASTTypeWriter::VisitSubstTemplateTypeParmType(
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM;
}
void
ASTTypeWriter::VisitSubstTemplateTypeParmPackType(
const SubstTemplateTypeParmPackType *T) {
Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record);
Writer.AddTemplateArgument(T->getArgumentPack(), Record);
Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK;
}
void
ASTTypeWriter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
@ -491,6 +499,10 @@ void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc(
SubstTemplateTypeParmTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
SubstTemplateTypeParmPackTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);

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

@ -11,3 +11,23 @@ struct X0 {
void test_X0() {
X0<int>().f<1, 2, 3, 4, 5>();
}
namespace PacksAtDifferentLevels {
template<typename...> struct tuple { };
template<typename T, typename U> struct pair { };
template<typename ...Types>
struct X {
template<typename> struct Inner;
template<typename ...YTypes>
struct Inner<tuple<pair<Types, YTypes>...> > {
static const unsigned zero = sizeof...(Types) - sizeof...(YTypes);
};
};
int check0[X<short, int, long>::Inner<tuple<pair<short, unsigned short>,
pair<int, unsigned int>,
pair<long, unsigned long>>
>::zero == 0? 1 : -1];
}