summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp59
-rw-r--r--clang/lib/Sema/TreeTransform.h47
2 files changed, 105 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 06afe87f515..b6bd6c03ff9 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -639,7 +639,7 @@ bool Sema::CheckParameterPacksForExpansion(
return true;
}
}
-
+
return false;
}
@@ -936,6 +936,63 @@ Sema::getTemplateArgumentPackExpansionPattern(
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
+ assert(Arg.containsUnexpandedParameterPack());
+
+ // If this is a substituted pack, grab that pack. If not, we don't know
+ // the size yet.
+ // FIXME: We could find a size in more cases by looking for a substituted
+ // pack anywhere within this argument, but that's not necessary in the common
+ // case for 'sizeof...(A)' handling.
+ TemplateArgument Pack;
+ switch (Arg.getKind()) {
+ case TemplateArgument::Type:
+ if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>())
+ Pack = Subst->getArgumentPack();
+ else
+ return None;
+ break;
+
+ case TemplateArgument::Expression:
+ if (auto *Subst =
+ dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
+ Pack = Subst->getArgumentPack();
+ else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
+ for (ParmVarDecl *PD : *Subst)
+ if (PD->isParameterPack())
+ return None;
+ return Subst->getNumExpansions();
+ } else
+ return None;
+ break;
+
+ case TemplateArgument::Template:
+ if (SubstTemplateTemplateParmPackStorage *Subst =
+ Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack())
+ Pack = Subst->getArgumentPack();
+ else
+ return None;
+ break;
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Pack:
+ case TemplateArgument::Null:
+ return None;
+ }
+
+ // Check that no argument in the pack is itself a pack expansion.
+ for (TemplateArgument Elem : Pack.pack_elements()) {
+ // There's no point recursing in this case; we would have already
+ // expanded this pack expansion into the enclosing pack if we could.
+ if (Elem.isPackExpansion())
+ return None;
+ }
+ return Pack.pack_size();
+}
+
static void CheckFoldOperand(Sema &S, Expr *E) {
if (!E)
return;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a74171ed5f8..6aa1dbbc442 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -10763,6 +10763,51 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
E->getRParenLoc(), None, None);
}
+ // Try to compute the result without performing a partial substitution.
+ Optional<unsigned> Result = 0;
+ for (const TemplateArgument &Arg : PackArgs) {
+ if (!Arg.isPackExpansion()) {
+ Result = *Result + 1;
+ continue;
+ }
+
+ TemplateArgumentLoc ArgLoc;
+ InventTemplateArgumentLoc(Arg, ArgLoc);
+
+ // Find the pattern of the pack expansion.
+ SourceLocation Ellipsis;
+ Optional<unsigned> OrigNumExpansions;
+ TemplateArgumentLoc Pattern =
+ getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis,
+ OrigNumExpansions);
+
+ // Substitute under the pack expansion. Do not expand the pack (yet).
+ TemplateArgumentLoc OutPattern;
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ if (getDerived().TransformTemplateArgument(Pattern, OutPattern,
+ /*Uneval*/ true))
+ return true;
+
+ // See if we can determine the number of arguments from the result.
+ Optional<unsigned> NumExpansions =
+ getSema().getFullyPackExpandedSize(OutPattern.getArgument());
+ if (!NumExpansions) {
+ // No: we must be in an alias template expansion, and we're going to need
+ // to actually expand the packs.
+ Result = None;
+ break;
+ }
+
+ Result = *Result + *NumExpansions;
+ }
+
+ // Common case: we could determine the number of expansions without
+ // substituting.
+ if (Result)
+ return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
+ E->getPackLoc(),
+ E->getRParenLoc(), *Result, None);
+
TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
E->getPackLoc());
{
@@ -10775,6 +10820,8 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
return ExprError();
}
+ // Check whether we managed to fully-expand the pack.
+ // FIXME: Is it possible for us to do so and not hit the early exit path?
SmallVector<TemplateArgument, 8> Args;
bool PartialSubstitution = false;
for (auto &Loc : TransformedPackArgs.arguments()) {
OpenPOWER on IntegriCloud