зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
4e26caa036
Коммит
c3069d618f
|
@ -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];
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче