forked from OSchip/llvm-project
1223 lines
44 KiB
C++
1223 lines
44 KiB
C++
//===------- SemaTemplateVariadic.cpp - C++ Variadic Templates ------------===/
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//===----------------------------------------------------------------------===/
|
|
//
|
|
// This file implements semantic analysis for C++0x variadic templates.
|
|
//===----------------------------------------------------------------------===/
|
|
|
|
#include "clang/Sema/Sema.h"
|
|
#include "TypeLocBuilder.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
|
#include "clang/AST/TypeLoc.h"
|
|
#include "clang/Sema/Lookup.h"
|
|
#include "clang/Sema/ParsedTemplate.h"
|
|
#include "clang/Sema/ScopeInfo.h"
|
|
#include "clang/Sema/SemaInternal.h"
|
|
#include "clang/Sema/Template.h"
|
|
|
|
using namespace clang;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Visitor that collects unexpanded parameter packs
|
|
//----------------------------------------------------------------------------
|
|
|
|
namespace {
|
|
/// A class that collects unexpanded parameter packs.
|
|
class CollectUnexpandedParameterPacksVisitor :
|
|
public RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor>
|
|
{
|
|
typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor>
|
|
inherited;
|
|
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
|
|
|
|
bool InLambda = false;
|
|
unsigned DepthLimit = (unsigned)-1;
|
|
|
|
void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
|
|
if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) {
|
|
// For now, the only problematic case is a generic lambda's templated
|
|
// call operator, so we don't need to look for all the other ways we
|
|
// could have reached a dependent parameter pack.
|
|
auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
|
|
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
|
|
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
|
|
return;
|
|
} else if (getDepthAndIndex(ND).first >= DepthLimit)
|
|
return;
|
|
|
|
Unexpanded.push_back({ND, Loc});
|
|
}
|
|
void addUnexpanded(const TemplateTypeParmType *T,
|
|
SourceLocation Loc = SourceLocation()) {
|
|
if (T->getDepth() < DepthLimit)
|
|
Unexpanded.push_back({T, Loc});
|
|
}
|
|
|
|
public:
|
|
explicit CollectUnexpandedParameterPacksVisitor(
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
|
|
: Unexpanded(Unexpanded) {}
|
|
|
|
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
|
|
|
//------------------------------------------------------------------------
|
|
// Recording occurrences of (unexpanded) parameter packs.
|
|
//------------------------------------------------------------------------
|
|
|
|
/// Record occurrences of template type parameter packs.
|
|
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
|
|
if (TL.getTypePtr()->isParameterPack())
|
|
addUnexpanded(TL.getTypePtr(), TL.getNameLoc());
|
|
return true;
|
|
}
|
|
|
|
/// Record occurrences of template type parameter packs
|
|
/// when we don't have proper source-location information for
|
|
/// them.
|
|
///
|
|
/// Ideally, this routine would never be used.
|
|
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
|
|
if (T->isParameterPack())
|
|
addUnexpanded(T);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Record occurrences of function and non-type template
|
|
/// parameter packs in an expression.
|
|
bool VisitDeclRefExpr(DeclRefExpr *E) {
|
|
if (E->getDecl()->isParameterPack())
|
|
addUnexpanded(E->getDecl(), E->getLocation());
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Record occurrences of template template parameter packs.
|
|
bool TraverseTemplateName(TemplateName Template) {
|
|
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
|
|
Template.getAsTemplateDecl())) {
|
|
if (TTP->isParameterPack())
|
|
addUnexpanded(TTP);
|
|
}
|
|
|
|
return inherited::TraverseTemplateName(Template);
|
|
}
|
|
|
|
/// Suppress traversal into Objective-C container literal
|
|
/// elements that are pack expansions.
|
|
bool TraverseObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
|
|
if (!E->containsUnexpandedParameterPack())
|
|
return true;
|
|
|
|
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
|
|
ObjCDictionaryElement Element = E->getKeyValueElement(I);
|
|
if (Element.isPackExpansion())
|
|
continue;
|
|
|
|
TraverseStmt(Element.Key);
|
|
TraverseStmt(Element.Value);
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------
|
|
// Pruning the search for unexpanded parameter packs.
|
|
//------------------------------------------------------------------------
|
|
|
|
/// Suppress traversal into statements and expressions that
|
|
/// do not contain unexpanded parameter packs.
|
|
bool TraverseStmt(Stmt *S) {
|
|
Expr *E = dyn_cast_or_null<Expr>(S);
|
|
if ((E && E->containsUnexpandedParameterPack()) || InLambda)
|
|
return inherited::TraverseStmt(S);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Suppress traversal into types that do not contain
|
|
/// unexpanded parameter packs.
|
|
bool TraverseType(QualType T) {
|
|
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
|
|
return inherited::TraverseType(T);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Suppress traversal into types with location information
|
|
/// that do not contain unexpanded parameter packs.
|
|
bool TraverseTypeLoc(TypeLoc TL) {
|
|
if ((!TL.getType().isNull() &&
|
|
TL.getType()->containsUnexpandedParameterPack()) ||
|
|
InLambda)
|
|
return inherited::TraverseTypeLoc(TL);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Suppress traversal of parameter packs.
|
|
bool TraverseDecl(Decl *D) {
|
|
// A function parameter pack is a pack expansion, so cannot contain
|
|
// an unexpanded parameter pack. Likewise for a template parameter
|
|
// pack that contains any references to other packs.
|
|
if (D && D->isParameterPack())
|
|
return true;
|
|
|
|
return inherited::TraverseDecl(D);
|
|
}
|
|
|
|
/// Suppress traversal of pack-expanded attributes.
|
|
bool TraverseAttr(Attr *A) {
|
|
if (A->isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseAttr(A);
|
|
}
|
|
|
|
/// Suppress traversal of pack expansion expressions and types.
|
|
///@{
|
|
bool TraversePackExpansionType(PackExpansionType *T) { return true; }
|
|
bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; }
|
|
bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; }
|
|
bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; }
|
|
|
|
///@}
|
|
|
|
/// Suppress traversal of using-declaration pack expansion.
|
|
bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
|
|
if (D->isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseUnresolvedUsingValueDecl(D);
|
|
}
|
|
|
|
/// Suppress traversal of using-declaration pack expansion.
|
|
bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
|
|
if (D->isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseUnresolvedUsingTypenameDecl(D);
|
|
}
|
|
|
|
/// Suppress traversal of template argument pack expansions.
|
|
bool TraverseTemplateArgument(const TemplateArgument &Arg) {
|
|
if (Arg.isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseTemplateArgument(Arg);
|
|
}
|
|
|
|
/// Suppress traversal of template argument pack expansions.
|
|
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
|
|
if (ArgLoc.getArgument().isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
|
|
}
|
|
|
|
/// Suppress traversal of base specifier pack expansions.
|
|
bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
|
|
if (Base.isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseCXXBaseSpecifier(Base);
|
|
}
|
|
|
|
/// Suppress traversal of mem-initializer pack expansions.
|
|
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
|
|
if (Init->isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseConstructorInitializer(Init);
|
|
}
|
|
|
|
/// Note whether we're traversing a lambda containing an unexpanded
|
|
/// parameter pack. In this case, the unexpanded pack can occur anywhere,
|
|
/// including all the places where we normally wouldn't look. Within a
|
|
/// lambda, we don't propagate the 'contains unexpanded parameter pack' bit
|
|
/// outside an expression.
|
|
bool TraverseLambdaExpr(LambdaExpr *Lambda) {
|
|
// The ContainsUnexpandedParameterPack bit on a lambda is always correct,
|
|
// even if it's contained within another lambda.
|
|
if (!Lambda->containsUnexpandedParameterPack())
|
|
return true;
|
|
|
|
bool WasInLambda = InLambda;
|
|
unsigned OldDepthLimit = DepthLimit;
|
|
|
|
InLambda = true;
|
|
if (auto *TPL = Lambda->getTemplateParameterList())
|
|
DepthLimit = TPL->getDepth();
|
|
|
|
inherited::TraverseLambdaExpr(Lambda);
|
|
|
|
InLambda = WasInLambda;
|
|
DepthLimit = OldDepthLimit;
|
|
return true;
|
|
}
|
|
|
|
/// Suppress traversal within pack expansions in lambda captures.
|
|
bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
|
|
Expr *Init) {
|
|
if (C->isPackExpansion())
|
|
return true;
|
|
|
|
return inherited::TraverseLambdaCapture(Lambda, C, Init);
|
|
}
|
|
};
|
|
}
|
|
|
|
/// Determine whether it's possible for an unexpanded parameter pack to
|
|
/// be valid in this location. This only happens when we're in a declaration
|
|
/// that is nested within an expression that could be expanded, such as a
|
|
/// lambda-expression within a function call.
|
|
///
|
|
/// This is conservatively correct, but may claim that some unexpanded packs are
|
|
/// permitted when they are not.
|
|
bool Sema::isUnexpandedParameterPackPermitted() {
|
|
for (auto *SI : FunctionScopes)
|
|
if (isa<sema::LambdaScopeInfo>(SI))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// Diagnose all of the unexpanded parameter packs in the given
|
|
/// vector.
|
|
bool
|
|
Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
|
UnexpandedParameterPackContext UPPC,
|
|
ArrayRef<UnexpandedParameterPack> Unexpanded) {
|
|
if (Unexpanded.empty())
|
|
return false;
|
|
|
|
// If we are within a lambda expression and referencing a pack that is not
|
|
// a parameter of the lambda itself, that lambda contains an unexpanded
|
|
// parameter pack, and we are done.
|
|
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
|
|
// later.
|
|
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
|
|
for (unsigned N = FunctionScopes.size(); N; --N) {
|
|
sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
|
|
// We do not permit pack expansion that would duplicate a statement
|
|
// expression, not even within a lambda.
|
|
// FIXME: We could probably support this for statement expressions that do
|
|
// not contain labels, and for pack expansions that expand both the stmt
|
|
// expr and the enclosing lambda.
|
|
if (std::any_of(
|
|
Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
|
|
[](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; }))
|
|
break;
|
|
|
|
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
|
|
if (N == FunctionScopes.size()) {
|
|
for (auto &Param : Unexpanded) {
|
|
auto *PD = dyn_cast_or_null<ParmVarDecl>(
|
|
Param.first.dyn_cast<NamedDecl *>());
|
|
if (PD && PD->getDeclContext() == LSI->CallOperator)
|
|
LambdaParamPackReferences.push_back(Param);
|
|
}
|
|
}
|
|
|
|
// If we have references to a parameter pack of the innermost enclosing
|
|
// lambda, only diagnose those ones. We don't know whether any other
|
|
// unexpanded parameters referenced herein are actually unexpanded;
|
|
// they might be expanded at an outer level.
|
|
if (!LambdaParamPackReferences.empty()) {
|
|
Unexpanded = LambdaParamPackReferences;
|
|
break;
|
|
}
|
|
|
|
LSI->ContainsUnexpandedParameterPack = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SmallVector<SourceLocation, 4> Locations;
|
|
SmallVector<IdentifierInfo *, 4> Names;
|
|
llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown;
|
|
|
|
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
|
|
IdentifierInfo *Name = nullptr;
|
|
if (const TemplateTypeParmType *TTP
|
|
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
|
|
Name = TTP->getIdentifier();
|
|
else
|
|
Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
|
|
|
|
if (Name && NamesKnown.insert(Name).second)
|
|
Names.push_back(Name);
|
|
|
|
if (Unexpanded[I].second.isValid())
|
|
Locations.push_back(Unexpanded[I].second);
|
|
}
|
|
|
|
DiagnosticBuilder DB = Diag(Loc, diag::err_unexpanded_parameter_pack)
|
|
<< (int)UPPC << (int)Names.size();
|
|
for (size_t I = 0, E = std::min(Names.size(), (size_t)2); I != E; ++I)
|
|
DB << Names[I];
|
|
|
|
for (unsigned I = 0, N = Locations.size(); I != N; ++I)
|
|
DB << SourceRange(Locations[I]);
|
|
return true;
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
|
TypeSourceInfo *T,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
// C++0x [temp.variadic]p5:
|
|
// An appearance of a name of a parameter pack that is not expanded is
|
|
// ill-formed.
|
|
if (!T->getType()->containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
|
|
T->getTypeLoc());
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
// C++0x [temp.variadic]p5:
|
|
// An appearance of a name of a parameter pack that is not expanded is
|
|
// ill-formed.
|
|
if (!E->containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded);
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
// C++0x [temp.variadic]p5:
|
|
// An appearance of a name of a parameter pack that is not expanded is
|
|
// ill-formed.
|
|
if (!SS.getScopeRep() ||
|
|
!SS.getScopeRep()->containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseNestedNameSpecifier(SS.getScopeRep());
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
|
|
UPPC, Unexpanded);
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
// C++0x [temp.variadic]p5:
|
|
// An appearance of a name of a parameter pack that is not expanded is
|
|
// ill-formed.
|
|
switch (NameInfo.getName().getNameKind()) {
|
|
case DeclarationName::Identifier:
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
case DeclarationName::CXXOperatorName:
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
case DeclarationName::CXXUsingDirective:
|
|
case DeclarationName::CXXDeductionGuideName:
|
|
return false;
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
case DeclarationName::CXXDestructorName:
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
// FIXME: We shouldn't need this null check!
|
|
if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
|
|
return DiagnoseUnexpandedParameterPack(NameInfo.getLoc(), TSInfo, UPPC);
|
|
|
|
if (!NameInfo.getName().getCXXNameType()->containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
break;
|
|
}
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseType(NameInfo.getName().getCXXNameType());
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
|
TemplateName Template,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
|
|
if (Template.isNull() || !Template.containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseTemplateName(Template);
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
|
}
|
|
|
|
bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
|
|
UnexpandedParameterPackContext UPPC) {
|
|
if (Arg.getArgument().isNull() ||
|
|
!Arg.getArgument().containsUnexpandedParameterPack())
|
|
return false;
|
|
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseTemplateArgumentLoc(Arg);
|
|
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
|
return DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseTemplateArgument(Arg);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseTemplateArgumentLoc(Arg);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(QualType T,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(TypeLoc TL,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(
|
|
NestedNameSpecifierLoc NNS,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseNestedNameSpecifierLoc(NNS);
|
|
}
|
|
|
|
void Sema::collectUnexpandedParameterPacks(
|
|
const DeclarationNameInfo &NameInfo,
|
|
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
|
.TraverseDeclarationNameInfo(NameInfo);
|
|
}
|
|
|
|
|
|
ParsedTemplateArgument
|
|
Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
|
|
SourceLocation EllipsisLoc) {
|
|
if (Arg.isInvalid())
|
|
return Arg;
|
|
|
|
switch (Arg.getKind()) {
|
|
case ParsedTemplateArgument::Type: {
|
|
TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc);
|
|
if (Result.isInvalid())
|
|
return ParsedTemplateArgument();
|
|
|
|
return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(),
|
|
Arg.getLocation());
|
|
}
|
|
|
|
case ParsedTemplateArgument::NonType: {
|
|
ExprResult Result = ActOnPackExpansion(Arg.getAsExpr(), EllipsisLoc);
|
|
if (Result.isInvalid())
|
|
return ParsedTemplateArgument();
|
|
|
|
return ParsedTemplateArgument(Arg.getKind(), Result.get(),
|
|
Arg.getLocation());
|
|
}
|
|
|
|
case ParsedTemplateArgument::Template:
|
|
if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) {
|
|
SourceRange R(Arg.getLocation());
|
|
if (Arg.getScopeSpec().isValid())
|
|
R.setBegin(Arg.getScopeSpec().getBeginLoc());
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
|
<< R;
|
|
return ParsedTemplateArgument();
|
|
}
|
|
|
|
return Arg.getTemplatePackExpansion(EllipsisLoc);
|
|
}
|
|
llvm_unreachable("Unhandled template argument kind?");
|
|
}
|
|
|
|
TypeResult Sema::ActOnPackExpansion(ParsedType Type,
|
|
SourceLocation EllipsisLoc) {
|
|
TypeSourceInfo *TSInfo;
|
|
GetTypeFromParser(Type, &TSInfo);
|
|
if (!TSInfo)
|
|
return true;
|
|
|
|
TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None);
|
|
if (!TSResult)
|
|
return true;
|
|
|
|
return CreateParsedType(TSResult->getType(), TSResult);
|
|
}
|
|
|
|
TypeSourceInfo *
|
|
Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
|
|
Optional<unsigned> NumExpansions) {
|
|
// Create the pack expansion type and source-location information.
|
|
QualType Result = CheckPackExpansion(Pattern->getType(),
|
|
Pattern->getTypeLoc().getSourceRange(),
|
|
EllipsisLoc, NumExpansions);
|
|
if (Result.isNull())
|
|
return nullptr;
|
|
|
|
TypeLocBuilder TLB;
|
|
TLB.pushFullCopy(Pattern->getTypeLoc());
|
|
PackExpansionTypeLoc TL = TLB.push<PackExpansionTypeLoc>(Result);
|
|
TL.setEllipsisLoc(EllipsisLoc);
|
|
|
|
return TLB.getTypeSourceInfo(Context, Result);
|
|
}
|
|
|
|
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
|
|
SourceLocation EllipsisLoc,
|
|
Optional<unsigned> NumExpansions) {
|
|
// C++0x [temp.variadic]p5:
|
|
// The pattern of a pack expansion shall name one or more
|
|
// parameter packs that are not expanded by a nested pack
|
|
// expansion.
|
|
if (!Pattern->containsUnexpandedParameterPack()) {
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
|
<< PatternRange;
|
|
return QualType();
|
|
}
|
|
|
|
return Context.getPackExpansionType(Pattern, NumExpansions);
|
|
}
|
|
|
|
ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
|
|
return CheckPackExpansion(Pattern, EllipsisLoc, None);
|
|
}
|
|
|
|
ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
|
|
Optional<unsigned> NumExpansions) {
|
|
if (!Pattern)
|
|
return ExprError();
|
|
|
|
// C++0x [temp.variadic]p5:
|
|
// The pattern of a pack expansion shall name one or more
|
|
// parameter packs that are not expanded by a nested pack
|
|
// expansion.
|
|
if (!Pattern->containsUnexpandedParameterPack()) {
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
|
<< Pattern->getSourceRange();
|
|
return ExprError();
|
|
}
|
|
|
|
// Create the pack expansion expression and source-location information.
|
|
return new (Context)
|
|
PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
|
|
}
|
|
|
|
bool Sema::CheckParameterPacksForExpansion(
|
|
SourceLocation EllipsisLoc, SourceRange PatternRange,
|
|
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
|
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
|
|
bool &RetainExpansion, Optional<unsigned> &NumExpansions) {
|
|
ShouldExpand = true;
|
|
RetainExpansion = false;
|
|
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
|
|
bool HaveFirstPack = false;
|
|
Optional<unsigned> NumPartialExpansions;
|
|
SourceLocation PartiallySubstitutedPackLoc;
|
|
|
|
for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
|
|
end = Unexpanded.end();
|
|
i != end; ++i) {
|
|
// Compute the depth and index for this parameter pack.
|
|
unsigned Depth = 0, Index = 0;
|
|
IdentifierInfo *Name;
|
|
bool IsFunctionParameterPack = false;
|
|
|
|
if (const TemplateTypeParmType *TTP
|
|
= i->first.dyn_cast<const TemplateTypeParmType *>()) {
|
|
Depth = TTP->getDepth();
|
|
Index = TTP->getIndex();
|
|
Name = TTP->getIdentifier();
|
|
} else {
|
|
NamedDecl *ND = i->first.get<NamedDecl *>();
|
|
if (isa<ParmVarDecl>(ND))
|
|
IsFunctionParameterPack = true;
|
|
else
|
|
std::tie(Depth, Index) = getDepthAndIndex(ND);
|
|
|
|
Name = ND->getIdentifier();
|
|
}
|
|
|
|
// Determine the size of this argument pack.
|
|
unsigned NewPackSize;
|
|
if (IsFunctionParameterPack) {
|
|
// Figure out whether we're instantiating to an argument pack or not.
|
|
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
|
|
|
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
|
|
= CurrentInstantiationScope->findInstantiationOf(
|
|
i->first.get<NamedDecl *>());
|
|
if (Instantiation->is<DeclArgumentPack *>()) {
|
|
// We could expand this function parameter pack.
|
|
NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
|
|
} else {
|
|
// We can't expand this function parameter pack, so we can't expand
|
|
// the pack expansion.
|
|
ShouldExpand = false;
|
|
continue;
|
|
}
|
|
} else {
|
|
// If we don't have a template argument at this depth/index, then we
|
|
// cannot expand the pack expansion. Make a note of this, but we still
|
|
// want to check any parameter packs we *do* have arguments for.
|
|
if (Depth >= TemplateArgs.getNumLevels() ||
|
|
!TemplateArgs.hasTemplateArgument(Depth, Index)) {
|
|
ShouldExpand = false;
|
|
continue;
|
|
}
|
|
|
|
// Determine the size of the argument pack.
|
|
NewPackSize = TemplateArgs(Depth, Index).pack_size();
|
|
}
|
|
|
|
// C++0x [temp.arg.explicit]p9:
|
|
// Template argument deduction can extend the sequence of template
|
|
// arguments corresponding to a template parameter pack, even when the
|
|
// sequence contains explicitly specified template arguments.
|
|
if (!IsFunctionParameterPack && CurrentInstantiationScope) {
|
|
if (NamedDecl *PartialPack
|
|
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
|
|
unsigned PartialDepth, PartialIndex;
|
|
std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
|
|
if (PartialDepth == Depth && PartialIndex == Index) {
|
|
RetainExpansion = true;
|
|
// We don't actually know the new pack size yet.
|
|
NumPartialExpansions = NewPackSize;
|
|
PartiallySubstitutedPackLoc = i->second;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NumExpansions) {
|
|
// The is the first pack we've seen for which we have an argument.
|
|
// Record it.
|
|
NumExpansions = NewPackSize;
|
|
FirstPack.first = Name;
|
|
FirstPack.second = i->second;
|
|
HaveFirstPack = true;
|
|
continue;
|
|
}
|
|
|
|
if (NewPackSize != *NumExpansions) {
|
|
// C++0x [temp.variadic]p5:
|
|
// All of the parameter packs expanded by a pack expansion shall have
|
|
// the same number of arguments specified.
|
|
if (HaveFirstPack)
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
|
|
<< FirstPack.first << Name << *NumExpansions << NewPackSize
|
|
<< SourceRange(FirstPack.second) << SourceRange(i->second);
|
|
else
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
|
|
<< Name << *NumExpansions << NewPackSize
|
|
<< SourceRange(i->second);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If we're performing a partial expansion but we also have a full expansion,
|
|
// expand to the number of common arguments. For example, given:
|
|
//
|
|
// template<typename ...T> struct A {
|
|
// template<typename ...U> void f(pair<T, U>...);
|
|
// };
|
|
//
|
|
// ... a call to 'A<int, int>().f<int>' should expand the pack once and
|
|
// retain an expansion.
|
|
if (NumPartialExpansions) {
|
|
if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
|
|
NamedDecl *PartialPack =
|
|
CurrentInstantiationScope->getPartiallySubstitutedPack();
|
|
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
|
|
<< PartialPack << *NumPartialExpansions << *NumExpansions
|
|
<< SourceRange(PartiallySubstitutedPackLoc);
|
|
return true;
|
|
}
|
|
|
|
NumExpansions = NumPartialExpansions;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
|
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
|
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
|
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
|
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
|
|
|
|
Optional<unsigned> Result;
|
|
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
|
|
// Compute the depth and index for this parameter pack.
|
|
unsigned Depth;
|
|
unsigned Index;
|
|
|
|
if (const TemplateTypeParmType *TTP
|
|
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
|
|
Depth = TTP->getDepth();
|
|
Index = TTP->getIndex();
|
|
} else {
|
|
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
|
|
if (isa<ParmVarDecl>(ND)) {
|
|
// Function parameter pack.
|
|
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
|
|
|
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
|
|
= CurrentInstantiationScope->findInstantiationOf(
|
|
Unexpanded[I].first.get<NamedDecl *>());
|
|
if (Instantiation->is<Decl*>())
|
|
// The pattern refers to an unexpanded pack. We're not ready to expand
|
|
// this pack yet.
|
|
return None;
|
|
|
|
unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
|
|
assert((!Result || *Result == Size) && "inconsistent pack sizes");
|
|
Result = Size;
|
|
continue;
|
|
}
|
|
|
|
std::tie(Depth, Index) = getDepthAndIndex(ND);
|
|
}
|
|
if (Depth >= TemplateArgs.getNumLevels() ||
|
|
!TemplateArgs.hasTemplateArgument(Depth, Index))
|
|
// The pattern refers to an unknown template argument. We're not ready to
|
|
// expand this pack yet.
|
|
return None;
|
|
|
|
// Determine the size of the argument pack.
|
|
unsigned Size = TemplateArgs(Depth, Index).pack_size();
|
|
assert((!Result || *Result == Size) && "inconsistent pack sizes");
|
|
Result = Size;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
|
|
const DeclSpec &DS = D.getDeclSpec();
|
|
switch (DS.getTypeSpecType()) {
|
|
case TST_typename:
|
|
case TST_typeofType:
|
|
case TST_underlyingType:
|
|
case TST_atomic: {
|
|
QualType T = DS.getRepAsType().get();
|
|
if (!T.isNull() && T->containsUnexpandedParameterPack())
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
case TST_typeofExpr:
|
|
case TST_decltype:
|
|
if (DS.getRepAsExpr() &&
|
|
DS.getRepAsExpr()->containsUnexpandedParameterPack())
|
|
return true;
|
|
break;
|
|
|
|
case TST_unspecified:
|
|
case TST_void:
|
|
case TST_char:
|
|
case TST_wchar:
|
|
case TST_char8:
|
|
case TST_char16:
|
|
case TST_char32:
|
|
case TST_int:
|
|
case TST_int128:
|
|
case TST_half:
|
|
case TST_float:
|
|
case TST_double:
|
|
case TST_Accum:
|
|
case TST_Fract:
|
|
case TST_Float16:
|
|
case TST_float128:
|
|
case TST_bool:
|
|
case TST_decimal32:
|
|
case TST_decimal64:
|
|
case TST_decimal128:
|
|
case TST_enum:
|
|
case TST_union:
|
|
case TST_struct:
|
|
case TST_interface:
|
|
case TST_class:
|
|
case TST_auto:
|
|
case TST_auto_type:
|
|
case TST_decltype_auto:
|
|
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
|
|
#include "clang/Basic/OpenCLImageTypes.def"
|
|
case TST_unknown_anytype:
|
|
case TST_error:
|
|
break;
|
|
}
|
|
|
|
for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
|
|
const DeclaratorChunk &Chunk = D.getTypeObject(I);
|
|
switch (Chunk.Kind) {
|
|
case DeclaratorChunk::Pointer:
|
|
case DeclaratorChunk::Reference:
|
|
case DeclaratorChunk::Paren:
|
|
case DeclaratorChunk::Pipe:
|
|
case DeclaratorChunk::BlockPointer:
|
|
// These declarator chunks cannot contain any parameter packs.
|
|
break;
|
|
|
|
case DeclaratorChunk::Array:
|
|
if (Chunk.Arr.NumElts &&
|
|
Chunk.Arr.NumElts->containsUnexpandedParameterPack())
|
|
return true;
|
|
break;
|
|
case DeclaratorChunk::Function:
|
|
for (unsigned i = 0, e = Chunk.Fun.NumParams; i != e; ++i) {
|
|
ParmVarDecl *Param = cast<ParmVarDecl>(Chunk.Fun.Params[i].Param);
|
|
QualType ParamTy = Param->getType();
|
|
assert(!ParamTy.isNull() && "Couldn't parse type?");
|
|
if (ParamTy->containsUnexpandedParameterPack()) return true;
|
|
}
|
|
|
|
if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) {
|
|
for (unsigned i = 0; i != Chunk.Fun.getNumExceptions(); ++i) {
|
|
if (Chunk.Fun.Exceptions[i]
|
|
.Ty.get()
|
|
->containsUnexpandedParameterPack())
|
|
return true;
|
|
}
|
|
} else if (isComputedNoexcept(Chunk.Fun.getExceptionSpecType()) &&
|
|
Chunk.Fun.NoexceptExpr->containsUnexpandedParameterPack())
|
|
return true;
|
|
|
|
if (Chunk.Fun.hasTrailingReturnType()) {
|
|
QualType T = Chunk.Fun.getTrailingReturnType().get();
|
|
if (!T.isNull() && T->containsUnexpandedParameterPack())
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case DeclaratorChunk::MemberPointer:
|
|
if (Chunk.Mem.Scope().getScopeRep() &&
|
|
Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack())
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
namespace {
|
|
|
|
// Callback to only accept typo corrections that refer to parameter packs.
|
|
class ParameterPackValidatorCCC final : public CorrectionCandidateCallback {
|
|
public:
|
|
bool ValidateCandidate(const TypoCorrection &candidate) override {
|
|
NamedDecl *ND = candidate.getCorrectionDecl();
|
|
return ND && ND->isParameterPack();
|
|
}
|
|
|
|
std::unique_ptr<CorrectionCandidateCallback> clone() override {
|
|
return llvm::make_unique<ParameterPackValidatorCCC>(*this);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
/// Called when an expression computing the size of a parameter pack
|
|
/// is parsed.
|
|
///
|
|
/// \code
|
|
/// template<typename ...Types> struct count {
|
|
/// static const unsigned value = sizeof...(Types);
|
|
/// };
|
|
/// \endcode
|
|
///
|
|
//
|
|
/// \param OpLoc The location of the "sizeof" keyword.
|
|
/// \param Name The name of the parameter pack whose size will be determined.
|
|
/// \param NameLoc The source location of the name of the parameter pack.
|
|
/// \param RParenLoc The location of the closing parentheses.
|
|
ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
|
|
SourceLocation OpLoc,
|
|
IdentifierInfo &Name,
|
|
SourceLocation NameLoc,
|
|
SourceLocation RParenLoc) {
|
|
// C++0x [expr.sizeof]p5:
|
|
// The identifier in a sizeof... expression shall name a parameter pack.
|
|
LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName);
|
|
LookupName(R, S);
|
|
|
|
NamedDecl *ParameterPack = nullptr;
|
|
switch (R.getResultKind()) {
|
|
case LookupResult::Found:
|
|
ParameterPack = R.getFoundDecl();
|
|
break;
|
|
|
|
case LookupResult::NotFound:
|
|
case LookupResult::NotFoundInCurrentInstantiation: {
|
|
ParameterPackValidatorCCC CCC{};
|
|
if (TypoCorrection Corrected =
|
|
CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr,
|
|
CCC, CTK_ErrorRecovery)) {
|
|
diagnoseTypo(Corrected,
|
|
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
|
|
PDiag(diag::note_parameter_pack_here));
|
|
ParameterPack = Corrected.getCorrectionDecl();
|
|
}
|
|
break;
|
|
}
|
|
case LookupResult::FoundOverloaded:
|
|
case LookupResult::FoundUnresolvedValue:
|
|
break;
|
|
|
|
case LookupResult::Ambiguous:
|
|
DiagnoseAmbiguousLookup(R);
|
|
return ExprError();
|
|
}
|
|
|
|
if (!ParameterPack || !ParameterPack->isParameterPack()) {
|
|
Diag(NameLoc, diag::err_sizeof_pack_no_pack_name)
|
|
<< &Name;
|
|
return ExprError();
|
|
}
|
|
|
|
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
|
|
|
|
return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
|
|
RParenLoc);
|
|
}
|
|
|
|
TemplateArgumentLoc
|
|
Sema::getTemplateArgumentPackExpansionPattern(
|
|
TemplateArgumentLoc OrigLoc,
|
|
SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions) const {
|
|
const TemplateArgument &Argument = OrigLoc.getArgument();
|
|
assert(Argument.isPackExpansion());
|
|
switch (Argument.getKind()) {
|
|
case TemplateArgument::Type: {
|
|
// FIXME: We shouldn't ever have to worry about missing
|
|
// type-source info!
|
|
TypeSourceInfo *ExpansionTSInfo = OrigLoc.getTypeSourceInfo();
|
|
if (!ExpansionTSInfo)
|
|
ExpansionTSInfo = Context.getTrivialTypeSourceInfo(Argument.getAsType(),
|
|
Ellipsis);
|
|
PackExpansionTypeLoc Expansion =
|
|
ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
|
|
Ellipsis = Expansion.getEllipsisLoc();
|
|
|
|
TypeLoc Pattern = Expansion.getPatternLoc();
|
|
NumExpansions = Expansion.getTypePtr()->getNumExpansions();
|
|
|
|
// We need to copy the TypeLoc because TemplateArgumentLocs store a
|
|
// TypeSourceInfo.
|
|
// FIXME: Find some way to avoid the copy?
|
|
TypeLocBuilder TLB;
|
|
TLB.pushFullCopy(Pattern);
|
|
TypeSourceInfo *PatternTSInfo =
|
|
TLB.getTypeSourceInfo(Context, Pattern.getType());
|
|
return TemplateArgumentLoc(TemplateArgument(Pattern.getType()),
|
|
PatternTSInfo);
|
|
}
|
|
|
|
case TemplateArgument::Expression: {
|
|
PackExpansionExpr *Expansion
|
|
= cast<PackExpansionExpr>(Argument.getAsExpr());
|
|
Expr *Pattern = Expansion->getPattern();
|
|
Ellipsis = Expansion->getEllipsisLoc();
|
|
NumExpansions = Expansion->getNumExpansions();
|
|
return TemplateArgumentLoc(Pattern, Pattern);
|
|
}
|
|
|
|
case TemplateArgument::TemplateExpansion:
|
|
Ellipsis = OrigLoc.getTemplateEllipsisLoc();
|
|
NumExpansions = Argument.getNumTemplateExpansions();
|
|
return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
|
|
OrigLoc.getTemplateQualifierLoc(),
|
|
OrigLoc.getTemplateNameLoc());
|
|
|
|
case TemplateArgument::Declaration:
|
|
case TemplateArgument::NullPtr:
|
|
case TemplateArgument::Template:
|
|
case TemplateArgument::Integral:
|
|
case TemplateArgument::Pack:
|
|
case TemplateArgument::Null:
|
|
return TemplateArgumentLoc();
|
|
}
|
|
|
|
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;
|
|
|
|
E = E->IgnoreImpCasts();
|
|
auto *OCE = dyn_cast<CXXOperatorCallExpr>(E);
|
|
if ((OCE && OCE->isInfixBinaryOp()) || isa<BinaryOperator>(E) ||
|
|
isa<AbstractConditionalOperator>(E)) {
|
|
S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand)
|
|
<< E->getSourceRange()
|
|
<< FixItHint::CreateInsertion(E->getBeginLoc(), "(")
|
|
<< FixItHint::CreateInsertion(E->getEndLoc(), ")");
|
|
}
|
|
}
|
|
|
|
ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
|
|
tok::TokenKind Operator,
|
|
SourceLocation EllipsisLoc, Expr *RHS,
|
|
SourceLocation RParenLoc) {
|
|
// LHS and RHS must be cast-expressions. We allow an arbitrary expression
|
|
// in the parser and reduce down to just cast-expressions here.
|
|
CheckFoldOperand(*this, LHS);
|
|
CheckFoldOperand(*this, RHS);
|
|
|
|
auto DiscardOperands = [&] {
|
|
CorrectDelayedTyposInExpr(LHS);
|
|
CorrectDelayedTyposInExpr(RHS);
|
|
};
|
|
|
|
// [expr.prim.fold]p3:
|
|
// In a binary fold, op1 and op2 shall be the same fold-operator, and
|
|
// either e1 shall contain an unexpanded parameter pack or e2 shall contain
|
|
// an unexpanded parameter pack, but not both.
|
|
if (LHS && RHS &&
|
|
LHS->containsUnexpandedParameterPack() ==
|
|
RHS->containsUnexpandedParameterPack()) {
|
|
DiscardOperands();
|
|
return Diag(EllipsisLoc,
|
|
LHS->containsUnexpandedParameterPack()
|
|
? diag::err_fold_expression_packs_both_sides
|
|
: diag::err_pack_expansion_without_parameter_packs)
|
|
<< LHS->getSourceRange() << RHS->getSourceRange();
|
|
}
|
|
|
|
// [expr.prim.fold]p2:
|
|
// In a unary fold, the cast-expression shall contain an unexpanded
|
|
// parameter pack.
|
|
if (!LHS || !RHS) {
|
|
Expr *Pack = LHS ? LHS : RHS;
|
|
assert(Pack && "fold expression with neither LHS nor RHS");
|
|
DiscardOperands();
|
|
if (!Pack->containsUnexpandedParameterPack())
|
|
return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
|
<< Pack->getSourceRange();
|
|
}
|
|
|
|
BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);
|
|
return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
|
|
None);
|
|
}
|
|
|
|
ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
|
|
BinaryOperatorKind Operator,
|
|
SourceLocation EllipsisLoc, Expr *RHS,
|
|
SourceLocation RParenLoc,
|
|
Optional<unsigned> NumExpansions) {
|
|
return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
|
|
Operator, EllipsisLoc, RHS, RParenLoc,
|
|
NumExpansions);
|
|
}
|
|
|
|
ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
|
|
BinaryOperatorKind Operator) {
|
|
// [temp.variadic]p9:
|
|
// If N is zero for a unary fold-expression, the value of the expression is
|
|
// && -> true
|
|
// || -> false
|
|
// , -> void()
|
|
// if the operator is not listed [above], the instantiation is ill-formed.
|
|
//
|
|
// Note that we need to use something like int() here, not merely 0, to
|
|
// prevent the result from being a null pointer constant.
|
|
QualType ScalarType;
|
|
switch (Operator) {
|
|
case BO_LOr:
|
|
return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false);
|
|
case BO_LAnd:
|
|
return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_true);
|
|
case BO_Comma:
|
|
ScalarType = Context.VoidTy;
|
|
break;
|
|
|
|
default:
|
|
return Diag(EllipsisLoc, diag::err_fold_expression_empty)
|
|
<< BinaryOperator::getOpcodeStr(Operator);
|
|
}
|
|
|
|
return new (Context) CXXScalarValueInitExpr(
|
|
ScalarType, Context.getTrivialTypeSourceInfo(ScalarType, EllipsisLoc),
|
|
EllipsisLoc);
|
|
}
|