aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-01-14 23:41:42 +0000
committerDouglas Gregor <dgregor@apple.com>2011-01-14 23:41:42 +0000
commit2be29f423acad3bbe39099a78db2805acb5bdf17 (patch)
tree9f0cf2a12cef339c6f54a06ed7c9445d60bb5875
parent6a24bfda084f06a0b252b7befe8cbb17fce7f94e (diff)
Teach template template argument pack expansions to keep track of the
number of expansions, when we know it, and propagate that information through Sema. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123493 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/TemplateBase.h55
-rw-r--r--lib/AST/ASTContext.cpp2
-rw-r--r--lib/AST/ASTImporter.cpp2
-rw-r--r--lib/AST/DeclTemplate.cpp5
-rw-r--r--lib/AST/TemplateBase.cpp12
-rw-r--r--lib/Sema/SemaTemplate.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp5
-rw-r--r--lib/Sema/TreeTransform.h2
-rw-r--r--lib/Serialization/ASTReader.cpp6
-rw-r--r--lib/Serialization/ASTWriter.cpp6
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp38
11 files changed, 117 insertions, 24 deletions
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 93ec35bebe..a4e074e083 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -80,8 +80,14 @@ private:
const TemplateArgument *Args;
unsigned NumArgs;
} Args;
+ struct {
+ void *Name;
+ unsigned NumExpansions;
+ } TemplateArg;
};
+ TemplateArgument(TemplateName, bool); // DO NOT USE
+
public:
/// \brief Construct an empty, invalid template argument.
TemplateArgument() : Kind(Null), TypeOrValue(0) { }
@@ -107,8 +113,7 @@ public:
Integer.Type = Type.getAsOpaquePtr();
}
- /// \brief Construct a template argument that is a template or a pack
- /// expansion of templates.
+ /// \brief Construct a template argument that is a template.
///
/// This form of template argument is generally used for template template
/// parameters. However, the template name could be a dependent template
@@ -116,13 +121,33 @@ public:
/// is taken.
///
/// \param Name The template name.
- /// \param PackExpansion Whether this template argument is a pack expansion.
- TemplateArgument(TemplateName Name, bool PackExpansion = false)
- : Kind(PackExpansion? TemplateExpansion : Template)
+ TemplateArgument(TemplateName Name) : Kind(Template)
{
- TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer());
+ TemplateArg.Name = Name.getAsVoidPointer();
+ TemplateArg.NumExpansions = 0;
}
-
+
+ /// \brief Construct a template argument that is a template pack expansion.
+ ///
+ /// This form of template argument is generally used for template template
+ /// parameters. However, the template name could be a dependent template
+ /// name that ends up being instantiated to a function template whose address
+ /// is taken.
+ ///
+ /// \param Name The template name.
+ ///
+ /// \param NumExpansions The number of expansions that will be generated by
+ /// instantiating
+ TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions)
+ : Kind(TemplateExpansion)
+ {
+ TemplateArg.Name = Name.getAsVoidPointer();
+ if (NumExpansions)
+ TemplateArg.NumExpansions = *NumExpansions + 1;
+ else
+ TemplateArg.NumExpansions = 0;
+ }
+
/// \brief Construct a template argument that is an expression.
///
/// This form of template argument only occurs in template argument
@@ -151,6 +176,9 @@ public:
} else if (Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = Other.Args.Args;
+ } else if (Kind == Template || Kind == TemplateExpansion) {
+ TemplateArg.Name = Other.TemplateArg.Name;
+ TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
} else
TypeOrValue = Other.TypeOrValue;
}
@@ -177,6 +205,9 @@ public:
} else if (Other.Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = Other.Args.Args;
+ } else if (Kind == Template || Kind == TemplateExpansion) {
+ TemplateArg.Name = Other.TemplateArg.Name;
+ TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
} else {
TypeOrValue = Other.TypeOrValue;
}
@@ -234,8 +265,7 @@ public:
if (Kind != Template)
return TemplateName();
- return TemplateName::getFromVoidPointer(
- reinterpret_cast<void*>(TypeOrValue));
+ return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
/// \brief Retrieve the template argument as a template name; if the argument
@@ -244,10 +274,13 @@ public:
if (Kind != Template && Kind != TemplateExpansion)
return TemplateName();
- return TemplateName::getFromVoidPointer(
- reinterpret_cast<void*>(TypeOrValue));
+ return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
+ /// \brief Retrieve the number of expansions that a template template argument
+ /// expansion will produce, if known.
+ llvm::Optional<unsigned> getNumTemplateExpansions() const;
+
/// \brief Retrieve the template argument as an integral value.
llvm::APSInt *getAsIntegral() {
if (Kind != Integral)
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a98e0636d4..e1e6fd08aa 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2768,7 +2768,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::TemplateExpansion:
return TemplateArgument(getCanonicalTemplateName(
Arg.getAsTemplateOrTemplatePattern()),
- true);
+ Arg.getNumTemplateExpansions());
case TemplateArgument::Integral:
return TemplateArgument(*Arg.getAsIntegral(),
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 7989b9f278..f9fe18f5df 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1823,7 +1823,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
if (ToTemplate.isNull())
return TemplateArgument();
- return TemplateArgument(ToTemplate, true);
+ return TemplateArgument(ToTemplate, From.getNumTemplateExpansions());
}
case TemplateArgument::Expression:
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index e7902e996a..b6716b34bd 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -337,7 +337,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- Arg = TemplateArgument(TemplateName(TTP), TTP->isParameterPack());
+ if (TTP->isParameterPack())
+ Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ else
+ Arg = TemplateArgument(TemplateName(TTP));
}
if ((*Param)->isTemplateParameterPack())
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 26c0c08971..f3def3eff2 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -135,6 +135,14 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return false;
}
+llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+ assert(Kind == TemplateExpansion);
+ if (TemplateArg.NumExpansions)
+ return TemplateArg.NumExpansions - 1;
+
+ return llvm::Optional<unsigned>();
+}
+
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context) const {
ID.AddInteger(Kind);
@@ -223,7 +231,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
return cast<PackExpansionExpr>(getAsExpr())->getPattern();
case TemplateExpansion:
- return TemplateArgument(getAsTemplateOrTemplatePattern(), false);
+ return TemplateArgument(getAsTemplateOrTemplatePattern());
case Declaration:
case Integral:
@@ -389,8 +397,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
}
case TemplateArgument::TemplateExpansion:
- // FIXME: Variadic templates num expansions
Ellipsis = getTemplateEllipsisLoc();
+ NumExpansions = Argument.getNumTemplateExpansions();
return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
getTemplateQualifierRange(),
getTemplateNameLoc());
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5101b3b525..3c9d386f81 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -467,8 +467,12 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
case ParsedTemplateArgument::Template: {
TemplateName Template = Arg.getAsTemplate().get();
- return TemplateArgumentLoc(TemplateArgument(Template,
- Arg.getEllipsisLoc().isValid()),
+ TemplateArgument TArg;
+ if (Arg.getEllipsisLoc().isValid())
+ TArg = TemplateArgument(Template, llvm::Optional<unsigned int>());
+ else
+ TArg = Template;
+ return TemplateArgumentLoc(TArg,
Arg.getScopeSpec().getRange(),
Arg.getLocation(),
Arg.getEllipsisLoc());
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 13cc17ef53..17b38bc1de 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -809,11 +809,8 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
- if (getSema().ArgumentPackSubstitutionIndex == -1) {
- // FIXME: Variadic templates fun case.
- getSema().Diag(Loc, diag::err_pack_expansion_mismatch_unsupported);
+ if (getSema().ArgumentPackSubstitutionIndex == -1)
return 0;
- }
assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 4abcb88fc0..02c95bdb13 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2188,7 +2188,7 @@ public:
case TemplateArgument::Template:
return TemplateArgumentLoc(TemplateArgument(
Pattern.getArgument().getAsTemplate(),
- true),
+ NumExpansions),
Pattern.getTemplateQualifierRange(),
Pattern.getTemplateNameLoc(),
EllipsisLoc);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 2c52f7f3a0..c6ecdea410 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4290,9 +4290,13 @@ ASTReader::ReadTemplateArgument(PerFileData &F,
return TemplateArgument(Value, T);
}
case TemplateArgument::Template:
+ return TemplateArgument(ReadTemplateName(Record, Idx));
case TemplateArgument::TemplateExpansion: {
TemplateName Name = ReadTemplateName(Record, Idx);
- return TemplateArgument(Name, Kind == TemplateArgument::TemplateExpansion);
+ llvm::Optional<unsigned> NumTemplateExpansions;
+ if (unsigned NumExpansions = Record[Idx++])
+ NumTemplateExpansions = NumExpansions - 1;
+ return TemplateArgument(Name, NumTemplateExpansions);
}
case TemplateArgument::Expression:
return TemplateArgument(ReadExpr(F));
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 00d46bc660..54a2648cd3 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -3231,8 +3231,14 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
AddTypeRef(Arg.getIntegralType(), Record);
break;
case TemplateArgument::Template:
+ AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+ break;
case TemplateArgument::TemplateExpansion:
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
+ if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+ Record.push_back(*NumExpansions + 1);
+ else
+ Record.push_back(0);
break;
case TemplateArgument::Expression:
AddStmt(Arg.getAsExpr());
diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 64554ab634..5ce5e63adb 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -88,4 +88,42 @@ namespace PacksAtDifferentLevels {
pair<int, unsigned int>,
pair<long, unsigned long>)
>::value == 1? 1 : -1];
+
+ template<typename T, typename U>
+ struct some_function_object {
+ template<typename>
+ struct result_of;
+ };
+
+ template<template<class> class...> struct metafun_tuple { };
+
+ template<typename ...Types1>
+ struct X3 {
+ template<typename, typename> struct Inner {
+ static const unsigned value = 0;
+ };
+
+ template<typename ...Types2>
+ struct Inner<tuple<pair<Types1, Types2>...>,
+ metafun_tuple<some_function_object<Types1, Types2>::template result_of...> > {
+ static const unsigned value = 1;
+ };
+ };
+
+ int check6[X3<short, int, long>::Inner<tuple<pair<short, unsigned short>,
+ pair<int, unsigned int>,
+ pair<long, unsigned long>>,
+ metafun_tuple<
+ some_function_object<short, unsigned short>::result_of,
+ some_function_object<int, unsigned int>::result_of,
+ some_function_object<long, unsigned long>::result_of>
+ >::value == 1? 1 : -1];
+ int check7[X3<short, int>::Inner<tuple<pair<short, unsigned short>,
+ pair<int, unsigned int>,
+ pair<long, unsigned long>>,
+ metafun_tuple<
+ some_function_object<short, unsigned short>::result_of,
+ some_function_object<int, unsigned int>::result_of,
+ some_function_object<long, unsigned long>::result_of>
+ >::value == 0? 1 : -1];
}