#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;
namespace {
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 *VD = dyn_cast<VarDecl>(ND)) {
auto *FD = dyn_cast<FunctionDecl>(VD->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; }
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
if (TL.getTypePtr()->isParameterPack())
addUnexpanded(TL.getTypePtr(), TL.getNameLoc());
return true;
}
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
if (T->isParameterPack())
addUnexpanded(T);
return true;
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl()->isParameterPack())
addUnexpanded(E->getDecl(), E->getLocation());
return true;
}
bool TraverseTemplateName(TemplateName Template) {
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
Template.getAsTemplateDecl())) {
if (TTP->isParameterPack())
addUnexpanded(TTP);
}
return inherited::TraverseTemplateName(Template);
}
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;
}
bool TraverseStmt(Stmt *S) {
Expr *E = dyn_cast_or_null<Expr>(S);
if ((E && E->containsUnexpandedParameterPack()) || InLambda)
return inherited::TraverseStmt(S);
return true;
}
bool TraverseType(QualType T) {
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
return inherited::TraverseType(T);
return true;
}
bool TraverseTypeLoc(TypeLoc TL) {
if ((!TL.getType().isNull() &&
TL.getType()->containsUnexpandedParameterPack()) ||
InLambda)
return inherited::TraverseTypeLoc(TL);
return true;
}
bool TraverseDecl(Decl *D) {
if (D && D->isParameterPack())
return true;
return inherited::TraverseDecl(D);
}
bool TraverseAttr(Attr *A) {
if (A->isPackExpansion())
return true;
return inherited::TraverseAttr(A);
}
bool TraversePackExpansionType(PackExpansionType *T) { return true; }
bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; }
bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; }
bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; }
bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
if (D->isPackExpansion())
return true;
return inherited::TraverseUnresolvedUsingValueDecl(D);
}
bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
if (D->isPackExpansion())
return true;
return inherited::TraverseUnresolvedUsingTypenameDecl(D);
}
bool TraverseTemplateArgument(const TemplateArgument &Arg) {
if (Arg.isPackExpansion())
return true;
return inherited::TraverseTemplateArgument(Arg);
}
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
if (ArgLoc.getArgument().isPackExpansion())
return true;
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
}
bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
if (Base.isPackExpansion())
return true;
return inherited::TraverseCXXBaseSpecifier(Base);
}
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
if (Init->isPackExpansion())
return true;
return inherited::TraverseConstructorInitializer(Init);
}
bool TraverseLambdaExpr(LambdaExpr *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;
}
bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
Expr *Init) {
if (C->isPackExpansion())
return true;
return inherited::TraverseLambdaCapture(Lambda, C, Init);
}
};
}
bool Sema::isUnexpandedParameterPackPermitted() {
for (auto *SI : FunctionScopes)
if (isa<sema::LambdaScopeInfo>(SI))
return true;
return false;
}
bool
Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
UnexpandedParameterPackContext UPPC,
ArrayRef<UnexpandedParameterPack> Unexpanded) {
if (Unexpanded.empty())
return false;
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
if (auto *LSI = getEnclosingLambda()) {
for (auto &Pack : Unexpanded) {
auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
return TTPD && TTPD->getTypeForDecl() == TTPT;
}
return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
}
if (LambdaParamPackReferences.empty()) {
bool EnclosingStmtExpr = false;
for (unsigned N = FunctionScopes.size(); N; --N) {
sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
if (llvm::any_of(
Func->CompoundScopes,
[](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) {
EnclosingStmtExpr = true;
break;
}
if (Func == LSI)
break;
}
if (!EnclosingStmtExpr) {
LSI->ContainsUnexpandedParameterPack = true;
return false;
}
} else {
Unexpanded = LambdaParamPackReferences;
}
}
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);
}
auto 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) {
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) {
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::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) {
if (!RE->containsUnexpandedParameterPack())
return false;
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(RE);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
auto Parms = RE->getLocalParameters();
llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end());
SmallVector<UnexpandedParameterPack, 2> UnexpandedParms;
for (auto Parm : Unexpanded)
if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl*>()))
UnexpandedParms.push_back(Parm);
if (UnexpandedParms.empty())
return false;
return DiagnoseUnexpandedParameterPacks(RE->getBeginLoc(), UPPC_Requirement,
UnexpandedParms);
}
bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
UnexpandedParameterPackContext UPPC) {
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) {
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:
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) {
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) {
if (!Pattern->containsUnexpandedParameterPack() &&
!Pattern->getContainedDeducedType()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< PatternRange;
return QualType();
}
return Context.getPackExpansionType(Pattern, NumExpansions,
false);
}
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();
if (!Pattern->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< Pattern->getSourceRange();
CorrectDelayedTyposInExpr(Pattern);
return ExprError();
}
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 (UnexpandedParameterPack ParmPack : Unexpanded) {
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
bool IsVarDeclPack = false;
if (const TemplateTypeParmType *TTP =
ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
} else {
NamedDecl *ND = ParmPack.first.get<NamedDecl *>();
if (isa<VarDecl>(ND))
IsVarDeclPack = true;
else
std::tie(Depth, Index) = getDepthAndIndex(ND);
Name = ND->getIdentifier();
}
unsigned NewPackSize;
if (IsVarDeclPack) {
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
CurrentInstantiationScope->findInstantiationOf(
ParmPack.first.get<NamedDecl *>());
if (Instantiation->is<DeclArgumentPack *>()) {
NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
} else {
ShouldExpand = false;
continue;
}
} else {
if (Depth >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Depth, Index)) {
ShouldExpand = false;
continue;
}
NewPackSize = TemplateArgs(Depth, Index).pack_size();
}
if (!IsVarDeclPack && CurrentInstantiationScope) {
if (NamedDecl *PartialPack
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
unsigned PartialDepth, PartialIndex;
std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
if (PartialDepth == Depth && PartialIndex == Index) {
RetainExpansion = true;
NumPartialExpansions = NewPackSize;
PartiallySubstitutedPackLoc = ParmPack.second;
continue;
}
}
}
if (!NumExpansions) {
NumExpansions = NewPackSize;
FirstPack.first = Name;
FirstPack.second = ParmPack.second;
HaveFirstPack = true;
continue;
}
if (NewPackSize != *NumExpansions) {
if (HaveFirstPack)
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
<< FirstPack.first << Name << *NumExpansions << NewPackSize
<< SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
else
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
<< Name << *NumExpansions << NewPackSize
<< SourceRange(ParmPack.second);
return true;
}
}
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) {
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<VarDecl>(ND)) {
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
= CurrentInstantiationScope->findInstantiationOf(
Unexpanded[I].first.get<NamedDecl *>());
if (Instantiation->is<Decl*>())
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))
return None;
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:
case TST_bitint:
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_ibm128:
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:
case TST_BFloat16:
#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:
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;
}
}
if (Expr *TRC = D.getTrailingRequiresClause())
if (TRC->containsUnexpandedParameterPack())
return true;
return false;
}
namespace {
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 std::make_unique<ParameterPackValidatorCCC>(*this);
}
};
}
ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
SourceLocation OpLoc,
IdentifierInfo &Name,
SourceLocation NameLoc,
SourceLocation RParenLoc) {
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: {
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();
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(Context, 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());
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 (VarDecl *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;
}
for (TemplateArgument Elem : Pack.pack_elements()) {
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(Scope *S, SourceLocation LParenLoc, Expr *LHS,
tok::TokenKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc) {
CheckFoldOperand(*this, LHS);
CheckFoldOperand(*this, RHS);
auto DiscardOperands = [&] {
CorrectDelayedTyposInExpr(LHS);
CorrectDelayedTyposInExpr(RHS);
};
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();
}
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);
UnresolvedLookupExpr *ULE = nullptr;
{
UnresolvedSet<16> Functions;
LookupBinOp(S, EllipsisLoc, Opc, Functions);
if (!Functions.empty()) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(
BinaryOperator::getOverloadedOperator(Opc));
ExprResult Callee = CreateUnresolvedLookupExpr(
nullptr, NestedNameSpecifierLoc(),
DeclarationNameInfo(OpName, EllipsisLoc), Functions);
if (Callee.isInvalid())
return ExprError();
ULE = cast<UnresolvedLookupExpr>(Callee.get());
}
}
return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
None);
}
ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
SourceLocation LParenLoc, Expr *LHS,
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
Optional<unsigned> NumExpansions) {
return new (Context)
CXXFoldExpr(Context.DependentTy, Callee, LParenLoc, LHS, Operator,
EllipsisLoc, RHS, RParenLoc, NumExpansions);
}
ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
BinaryOperatorKind Operator) {
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);
}