640 lines
25 KiB
C++
640 lines
25 KiB
C++
//===--- SemaExpand.cpp - Semantic Analysis for Expansion Statements-------===//
|
|
//
|
|
// Copyright 2024 Bloomberg Finance L.P.
|
|
//
|
|
// 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 expansion statements.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DynamicRecursiveASTVisitor.h"
|
|
#include "clang/Basic/DiagnosticSema.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Sema/EnterExpressionEvaluationContext.h"
|
|
#include "clang/Sema/Initialization.h"
|
|
#include "clang/Sema/Lookup.h"
|
|
#include "clang/Sema/Overload.h"
|
|
#include "clang/Sema/Sema.h"
|
|
#include "clang/Sema/Template.h"
|
|
|
|
|
|
using namespace clang;
|
|
using namespace sema;
|
|
|
|
namespace {
|
|
|
|
VarDecl *ExtractVarDecl(Stmt *S) {
|
|
if (auto *DS = dyn_cast_or_null<DeclStmt>(S); S)
|
|
if (Decl *D = DS->getSingleDecl(); D && !D->isInvalidDecl())
|
|
return dyn_cast<VarDecl>(D);
|
|
return nullptr;
|
|
}
|
|
|
|
unsigned ExtractParmVarDeclDepth(Expr *E) {
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
|
|
if (auto *PVD = cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
|
|
return PVD->getDepth();
|
|
} else if (auto *SNTTPE = cast<SubstNonTypeTemplateParmExpr>(E)) {
|
|
if (auto *PVD = cast<NonTypeTemplateParmDecl>(SNTTPE->getAssociatedDecl()))
|
|
return PVD->getDepth();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ExprResult makeIterableExpansionSizeExpr(Sema &S, VarDecl *RangeVar) {
|
|
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
|
|
if (RangeVar->isConstexpr())
|
|
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
|
|
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
|
|
|
|
SourceLocation RangeLoc = RangeVar->getBeginLoc();
|
|
|
|
DeclarationNameInfo BeginName(&S.PP.getIdentifierTable().get("begin"),
|
|
RangeLoc);
|
|
LookupResult BeginLR(S, BeginName, Sema::LookupMemberName);
|
|
{
|
|
if (auto *RD = RangeVar->getType()->getAsCXXRecordDecl())
|
|
S.LookupQualifiedName(BeginLR, RD);
|
|
}
|
|
|
|
DeclarationNameInfo EndName(&S.PP.getIdentifierTable().get("end"), RangeLoc);
|
|
LookupResult EndLR(S, EndName, Sema::LookupMemberName);
|
|
{
|
|
if (auto *RD = RangeVar->getType()->getAsCXXRecordDecl())
|
|
S.LookupQualifiedName(EndLR, RD);
|
|
}
|
|
|
|
Expr *VarRef;
|
|
{
|
|
DeclarationNameInfo Name(RangeVar->getDeclName(), RangeVar->getBeginLoc());
|
|
VarRef = S.BuildDeclRefExpr(RangeVar, RangeVar->getType(), VK_LValue, Name,
|
|
nullptr, RangeVar);
|
|
}
|
|
assert(VarRef);
|
|
|
|
ExprResult BeginResult;
|
|
{
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
OverloadCandidateSet::CSK_Normal);
|
|
Sema::ForRangeStatus Status =
|
|
S.BuildForRangeBeginEndCall(RangeLoc, RangeLoc, BeginName, BeginLR,
|
|
&CandidateSet, VarRef, &BeginResult);
|
|
if (Status != Sema::FRS_Success)
|
|
return ExprError();
|
|
assert(!BeginResult.isInvalid());
|
|
}
|
|
Expr *Begin = BeginResult.get();
|
|
|
|
ExprResult EndResult;
|
|
{
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
OverloadCandidateSet::CSK_Normal);
|
|
Sema::ForRangeStatus Status =
|
|
S.BuildForRangeBeginEndCall(RangeLoc, RangeLoc, EndName, EndLR,
|
|
&CandidateSet, VarRef, &EndResult);
|
|
if (Status != Sema::FRS_Success)
|
|
return ExprError();
|
|
assert(!EndResult.isInvalid());
|
|
}
|
|
Expr *End = EndResult.get();
|
|
|
|
OverloadedOperatorKind Op = OO_Minus;
|
|
DeclarationName OpName(S.Context.DeclarationNames.getCXXOperatorName(Op));
|
|
|
|
Expr *Args[2] = {EndResult.get(), BeginResult.get()};
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
OverloadCandidateSet::CSK_Operator);
|
|
S.AddArgumentDependentLookupCandidates(OpName, RangeLoc, Args, nullptr,
|
|
CandidateSet);
|
|
|
|
UnresolvedSet<4> Fns;
|
|
S.AddFunctionCandidates(Fns, Args, CandidateSet);
|
|
|
|
return S.MaybeCreateExprWithCleanups(
|
|
S.CreateOverloadedBinOp(RangeLoc, BO_Sub, Fns, End, Begin));
|
|
}
|
|
|
|
// Returns 'true' if the 'Range' is an iterable expression, and 'false'
|
|
// otherwise. If 'true', then 'Result' contains the resulting
|
|
// 'CXXIterableExpansionSelectExpr' (or error).
|
|
bool tryMakeCXXIterableExpansionSelectExpr(
|
|
Sema &S, Expr *Range, Expr *TParamRef, VarDecl *ExpansionVar,
|
|
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
|
|
ExprResult &SelectResult) {
|
|
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
|
|
if (ExpansionVar->isConstexpr())
|
|
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
|
|
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
|
|
|
|
if (Range->getType()->isArrayType())
|
|
return false;
|
|
SourceLocation RangeLoc = Range->getExprLoc();
|
|
|
|
DeclarationNameInfo BeginName(&S.PP.getIdentifierTable().get("begin"),
|
|
RangeLoc);
|
|
LookupResult BeginLR(S, BeginName, Sema::LookupMemberName);
|
|
{
|
|
if (auto *RD = Range->getType()->getAsCXXRecordDecl())
|
|
S.LookupQualifiedName(BeginLR, RD);
|
|
}
|
|
|
|
VarDecl *RangeVar;
|
|
Expr *VarRef;
|
|
{
|
|
assert(isa<ExpansionStmtDecl>(S.CurContext));
|
|
DeclContext *DC = S.CurContext;
|
|
while (isa<ExpansionStmtDecl>(DC))
|
|
DC = DC->getParent();
|
|
|
|
IdentifierInfo *II = &S.PP.getIdentifierTable().get("__range");
|
|
QualType QT = Range->getType().withConst();
|
|
TypeSourceInfo *TSI = S.Context.getTrivialTypeSourceInfo(QT);
|
|
|
|
RangeVar = VarDecl::Create(S.Context, DC, Range->getBeginLoc(),
|
|
Range->getBeginLoc(), II, QT, TSI, SC_Auto);
|
|
if (ExpansionVar->isConstexpr())
|
|
RangeVar->setConstexpr(true);
|
|
else if (!LifetimeExtendTemps.empty()) {
|
|
InitializedEntity Entity =
|
|
InitializedEntity::InitializeVariable(RangeVar);
|
|
for (auto *MTE : LifetimeExtendTemps)
|
|
MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
|
|
}
|
|
|
|
S.AddInitializerToDecl(RangeVar, Range, false);
|
|
if (RangeVar->isInvalidDecl())
|
|
return false;
|
|
|
|
DeclarationNameInfo Name(II, Range->getBeginLoc());
|
|
VarRef = S.BuildDeclRefExpr(RangeVar, Range->getType(), VK_LValue, Name,
|
|
nullptr, RangeVar);
|
|
}
|
|
|
|
ExprResult BeginResult;
|
|
{
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
OverloadCandidateSet::CSK_Normal);
|
|
Sema::ForRangeStatus Status =
|
|
S.BuildForRangeBeginEndCall(RangeLoc, RangeLoc, BeginName, BeginLR,
|
|
&CandidateSet, VarRef, &BeginResult);
|
|
if (Status != Sema::FRS_Success)
|
|
return false;
|
|
assert(!BeginResult.isInvalid());
|
|
}
|
|
Expr *Begin = BeginResult.get();
|
|
|
|
// Assume an error, unless we write something else.
|
|
SelectResult = ExprError();
|
|
|
|
OverloadedOperatorKind Op = OO_Plus;
|
|
DeclarationName OpName(S.Context.DeclarationNames.getCXXOperatorName(Op));
|
|
|
|
Expr *Args[2] = {Begin, TParamRef};
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
OverloadCandidateSet::CSK_Operator);
|
|
S.AddArgumentDependentLookupCandidates(OpName, RangeLoc, Args, nullptr,
|
|
CandidateSet);
|
|
|
|
UnresolvedSet<4> Fns;
|
|
S.AddFunctionCandidates(Fns, Args, CandidateSet);
|
|
|
|
ExprResult ER = S.CreateOverloadedBinOp(RangeLoc, BO_Add, Fns, Begin,
|
|
TParamRef);
|
|
if (ER.isInvalid())
|
|
return true;
|
|
Expr *UnaryArg[1] = {ER.get()};
|
|
|
|
Op = OO_Star;
|
|
OpName = S.Context.DeclarationNames.getCXXOperatorName(Op);
|
|
|
|
CandidateSet.clear(OverloadCandidateSet::CSK_Operator);
|
|
S.AddArgumentDependentLookupCandidates(OpName, RangeLoc, UnaryArg, nullptr,
|
|
CandidateSet);
|
|
|
|
Fns.clear();
|
|
S.AddFunctionCandidates(Fns, UnaryArg, CandidateSet);
|
|
|
|
ExprResult Impl = S.CreateOverloadedUnaryOp(RangeLoc, UO_Deref, Fns,
|
|
ER.get());
|
|
if (Impl.isInvalid())
|
|
return true;
|
|
|
|
SelectResult = S.BuildCXXIterableExpansionSelectExpr(RangeVar, Impl.get());
|
|
return true;
|
|
}
|
|
|
|
ExprResult makeCXXDestructurableExpansionSelectExpr(
|
|
Sema &S, Expr *Range, Expr *TParamRef, VarDecl *ExpansionVar,
|
|
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
|
|
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
|
|
if (ExpansionVar->isConstexpr())
|
|
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
|
|
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
|
|
|
|
UnsignedOrNone Arity = S.GetDecompositionElementCount(Range->getType(),
|
|
Range->getBeginLoc());
|
|
if (!Arity)
|
|
return ExprError();
|
|
|
|
QualType QT = S.Context.getAutoDeductType(); // TODO: Add ref support.
|
|
if (ExpansionVar->getType()->isReferenceType())
|
|
QT = S.BuildReferenceType(QT, true, Range->getBeginLoc(),
|
|
DeclarationName());
|
|
|
|
SmallVector<BindingDecl *, 4> Bindings;
|
|
for (size_t k = 0; k < *Arity; ++k) {
|
|
Bindings.push_back(BindingDecl::Create(S.Context, S.CurContext,
|
|
Range->getBeginLoc(),
|
|
/*IdentifierInfo=*/nullptr, QT));
|
|
}
|
|
|
|
TypeSourceInfo *TSI = S.Context.getTrivialTypeSourceInfo(QT);
|
|
DecompositionDecl *DD = DecompositionDecl::Create(S.Context, S.CurContext,
|
|
Range->getBeginLoc(),
|
|
Range->getBeginLoc(),
|
|
QT, TSI,
|
|
SC_Auto, Bindings);
|
|
if (ExpansionVar->isConstexpr())
|
|
DD->setConstexpr(true);
|
|
|
|
if (!LifetimeExtendTemps.empty()) {
|
|
InitializedEntity Entity = InitializedEntity::InitializeVariable(DD);
|
|
for (auto *MTE : LifetimeExtendTemps)
|
|
MTE->setExtendingDecl(DD, Entity.allocateManglingNumber());
|
|
}
|
|
|
|
S.AddInitializerToDecl(DD, Range, false);
|
|
|
|
return CXXDestructurableExpansionSelectExpr::Create(S.Context, DD,
|
|
TParamRef, ExpansionVar);
|
|
}
|
|
} // close anonymous namespace
|
|
|
|
StmtResult Sema::ActOnCXXExpansionStmt(
|
|
NonTypeTemplateParmDecl *NTTP, SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *Init,
|
|
Stmt *ExpansionVarStmt, SourceLocation ColonLoc, Expr *Range,
|
|
SourceLocation RParenLoc, BuildForRangeKind Kind,
|
|
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
|
|
if (!Range || Kind == BFRK_Check)
|
|
return StmtError();
|
|
|
|
// Build a 'DeclRefExpr' designating the template parameter '__N'.
|
|
ExprResult ER = BuildDeclRefExpr(NTTP, Context.getSizeType(), VK_PRValue,
|
|
ColonLoc);
|
|
if (ER.isInvalid())
|
|
return StmtError();
|
|
Expr *TParamRef = ER.get();
|
|
|
|
VarDecl *ExpansionVar = ExtractVarDecl(ExpansionVarStmt);
|
|
if (!ExpansionVar)
|
|
return StmtError();
|
|
|
|
ER = BuildCXXExpansionSelectExpr(Range, TParamRef, ExpansionVar,
|
|
LifetimeExtendTemps);
|
|
if (ER.isInvalid())
|
|
return StmtError();
|
|
Expr *Select = ER.get();
|
|
|
|
assert(!ExpansionVar->getInit());
|
|
AddInitializerToDecl(ExpansionVar, Select, false);
|
|
if (ExpansionVar->isInvalidDecl())
|
|
return StmtError();
|
|
|
|
return BuildCXXExpansionStmt(TemplateKWLoc, ForLoc, LParenLoc, Init,
|
|
ExpansionVarStmt, ColonLoc, RParenLoc,
|
|
TParamRef);
|
|
}
|
|
|
|
StmtResult Sema::BuildCXXExpansionStmt(SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc,
|
|
SourceLocation LParenLoc, Stmt *Init,
|
|
Stmt *ExpansionVarStmt,
|
|
SourceLocation ColonLoc,
|
|
SourceLocation RParenLoc,
|
|
Expr *TParamRef) {
|
|
VarDecl *ExpansionVar = ExtractVarDecl(ExpansionVarStmt);
|
|
if (!ExpansionVar)
|
|
return StmtError();
|
|
Expr *Select = ExpansionVar->getInit();
|
|
assert(Select);
|
|
|
|
if (auto *WithCleanups = dyn_cast<ExprWithCleanups>(Select))
|
|
Select = WithCleanups->getSubExpr();
|
|
|
|
if (isa<CXXExpansionInitListSelectExpr>(Select)) {
|
|
return BuildCXXInitListExpansionStmt(TemplateKWLoc, ForLoc, LParenLoc,
|
|
Init, ExpansionVarStmt, ColonLoc,
|
|
RParenLoc, TParamRef);
|
|
} else if (isa<CXXIndeterminateExpansionSelectExpr>(Select)) {
|
|
return BuildCXXIndeterminateExpansionStmt(TemplateKWLoc, ForLoc, LParenLoc,
|
|
Init, ExpansionVarStmt, ColonLoc,
|
|
RParenLoc, TParamRef);
|
|
} else if (isa<CXXDestructurableExpansionSelectExpr>(Select)) {
|
|
return BuildCXXDestructurableExpansionStmt(TemplateKWLoc, ForLoc, LParenLoc,
|
|
Init, ExpansionVarStmt, ColonLoc,
|
|
RParenLoc, TParamRef);
|
|
} else if (auto *IESE = dyn_cast<CXXIterableExpansionSelectExpr>(Select)) {
|
|
ExprResult Size = makeIterableExpansionSizeExpr(*this, IESE->getRangeVar());
|
|
if (Size.isInvalid()) {
|
|
Diag(IESE->getExprLoc(), diag::err_compute_expansion_size_index) << 0;
|
|
return StmtError();
|
|
}
|
|
return BuildCXXIterableExpansionStmt(TemplateKWLoc, ForLoc, LParenLoc, Init,
|
|
ExpansionVarStmt, ColonLoc, RParenLoc,
|
|
TParamRef, Size.get());
|
|
}
|
|
llvm_unreachable("unknown expansion select expression");
|
|
}
|
|
|
|
StmtResult
|
|
Sema::BuildCXXIndeterminateExpansionStmt(SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc,
|
|
SourceLocation LParenLoc,
|
|
Stmt *Init, Stmt *ExpansionVarStmt,
|
|
SourceLocation ColonLoc,
|
|
SourceLocation RParenLoc,
|
|
Expr *TParamRef) {
|
|
return CXXIndeterminateExpansionStmt::Create(
|
|
Context, Init, cast<DeclStmt>(ExpansionVarStmt), TemplateKWLoc,
|
|
ForLoc, LParenLoc, ColonLoc, RParenLoc, TParamRef);
|
|
}
|
|
|
|
StmtResult
|
|
Sema::BuildCXXIterableExpansionStmt(SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc,
|
|
SourceLocation LParenLoc,
|
|
Stmt *Init, Stmt *ExpansionVarStmt,
|
|
SourceLocation ColonLoc,
|
|
SourceLocation RParenLoc,
|
|
Expr *TParamRef, Expr *SizeExpr) {
|
|
unsigned NumExpansions = 0;
|
|
if (!SizeExpr->isValueDependent()) {
|
|
Expr::EvalResult ER;
|
|
SmallVector<PartialDiagnosticAt, 4> Notes;
|
|
ER.Diag = &Notes;
|
|
|
|
if (SizeExpr->EvaluateAsInt(ER, Context, Expr::SE_NoSideEffects,
|
|
/*InConstantContext=*/true))
|
|
NumExpansions = ER.Val.getInt().getZExtValue();
|
|
else {
|
|
Diag(SizeExpr->getExprLoc(), diag::err_compute_expansion_size_index) << 0;
|
|
for (auto D : Notes)
|
|
Diag(D.first, D.second);
|
|
|
|
return StmtError();
|
|
}
|
|
}
|
|
|
|
return CXXIterableExpansionStmt::Create(
|
|
Context, Init, cast<DeclStmt>(ExpansionVarStmt), SizeExpr,
|
|
NumExpansions, TemplateKWLoc, ForLoc, LParenLoc, ColonLoc, RParenLoc,
|
|
TParamRef);
|
|
}
|
|
|
|
StmtResult
|
|
Sema::BuildCXXDestructurableExpansionStmt(SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc,
|
|
SourceLocation LParenLoc,
|
|
Stmt *Init, Stmt *ExpansionVarStmt,
|
|
SourceLocation ColonLoc,
|
|
SourceLocation RParenLoc,
|
|
Expr *TParamRef) {
|
|
return CXXDestructurableExpansionStmt::Create(
|
|
Context, Init, cast<DeclStmt>(ExpansionVarStmt), TemplateKWLoc,
|
|
ForLoc, LParenLoc, ColonLoc, RParenLoc, TParamRef);
|
|
}
|
|
|
|
StmtResult Sema::BuildCXXInitListExpansionStmt(SourceLocation TemplateKWLoc,
|
|
SourceLocation ForLoc,
|
|
SourceLocation LParenLoc,
|
|
Stmt *Init,
|
|
Stmt *ExpansionVarStmt,
|
|
SourceLocation ColonLoc,
|
|
SourceLocation RParenLoc,
|
|
Expr *TParamRef) {
|
|
return CXXInitListExpansionStmt::Create(Context, Init,
|
|
cast<DeclStmt>(ExpansionVarStmt),
|
|
TemplateKWLoc, ForLoc, LParenLoc,
|
|
ColonLoc, RParenLoc, TParamRef);
|
|
}
|
|
|
|
ExprResult Sema::BuildCXXExpansionSelectExpr(
|
|
Expr *Range, Expr *TParamRef, VarDecl *ExpansionVar,
|
|
ArrayRef <MaterializeTemporaryExpr *> LifetimeExtendTemps) {
|
|
if (Range->containsErrors())
|
|
return ExprError();
|
|
|
|
if (auto *EILE = dyn_cast<CXXExpansionInitListExpr>(Range))
|
|
return BuildCXXExpansionInitListSelectExpr(EILE, TParamRef);
|
|
|
|
if (Range->isTypeDependent())
|
|
return BuildCXXIndeterminateExpansionSelectExpr(Range, TParamRef,
|
|
ExpansionVar,
|
|
LifetimeExtendTemps);
|
|
|
|
ExprResult IterableExprResult;
|
|
if (tryMakeCXXIterableExpansionSelectExpr(*this, Range, TParamRef,
|
|
ExpansionVar, LifetimeExtendTemps,
|
|
IterableExprResult))
|
|
return IterableExprResult;
|
|
|
|
return makeCXXDestructurableExpansionSelectExpr(*this, Range, TParamRef,
|
|
ExpansionVar,
|
|
LifetimeExtendTemps);
|
|
}
|
|
|
|
ExprResult
|
|
Sema::BuildCXXIndeterminateExpansionSelectExpr(
|
|
Expr *Range, Expr *TParamRef, VarDecl *ExpansionVar,
|
|
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
|
|
return CXXIndeterminateExpansionSelectExpr::Create(Context, Range, TParamRef,
|
|
ExpansionVar,
|
|
LifetimeExtendTemps);
|
|
}
|
|
|
|
ExprResult
|
|
Sema::BuildCXXIterableExpansionSelectExpr(VarDecl *RangeVar, Expr *Impl) {
|
|
if (Impl->isValueDependent())
|
|
return CXXIterableExpansionSelectExpr::Create(Context, RangeVar, Impl);
|
|
|
|
return Impl;
|
|
}
|
|
|
|
ExprResult
|
|
Sema::BuildCXXDestructurableExpansionSelectExpr(DecompositionDecl *DD,
|
|
Expr *Idx,
|
|
VarDecl *ExpansionVar) {
|
|
if (Idx->isValueDependent())
|
|
return CXXDestructurableExpansionSelectExpr::Create(Context, DD, Idx,
|
|
ExpansionVar);
|
|
|
|
Expr::EvalResult ER;
|
|
if (!Idx->EvaluateAsInt(ER, Context))
|
|
return ExprError();
|
|
unsigned I = ER.Val.getInt().getZExtValue();
|
|
assert(I < DD->bindings().size());
|
|
|
|
MarkAnyDeclReferenced(Idx->getBeginLoc(), DD, true);
|
|
if (auto *BD = DD->bindings()[I]; auto *HVD = BD->getHoldingVar())
|
|
return HVD->getInit();
|
|
else
|
|
return BD->getBinding();
|
|
}
|
|
|
|
ExprResult
|
|
Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
|
|
Expr *Idx) {
|
|
// Use 'CXXExpansionInitListSelectExpr' as a placeholder until tree transform.
|
|
if (Range->containsPack() || Idx->isValueDependent())
|
|
return CXXExpansionInitListSelectExpr::Create(Context, Range, Idx);
|
|
ArrayRef<Expr *> SubExprs = Range->getSubExprs();
|
|
|
|
// Evaluate the index.
|
|
Expr::EvalResult ER;
|
|
|
|
SmallVector<PartialDiagnosticAt, 4> Notes;
|
|
ER.Diag = &Notes;
|
|
|
|
if (!Idx->EvaluateAsInt(ER, Context)) {
|
|
Diag(Idx->getExprLoc(), diag::err_compute_expansion_size_index) << 1;
|
|
for (auto D : Notes)
|
|
Diag(D.first, D.second);
|
|
|
|
return ExprError();
|
|
}
|
|
size_t I = ER.Val.getInt().getZExtValue();
|
|
assert(I < SubExprs.size());
|
|
|
|
return SubExprs[I];
|
|
}
|
|
|
|
StmtResult Sema::FinishCXXExpansionStmt(Stmt *Heading, Stmt *Body) {
|
|
if (!Heading || !Body)
|
|
return StmtError();
|
|
|
|
// Diagnose identifier labels.
|
|
struct DiagnoseLabels : DynamicRecursiveASTVisitor {
|
|
Sema &SemaRef;
|
|
DiagnoseLabels(Sema &S) : SemaRef(S) {}
|
|
bool VisitLabelStmt(LabelStmt *S) override {
|
|
SemaRef.Diag(S->getIdentLoc(), diag::err_expanded_identifier_label);
|
|
return false;
|
|
}
|
|
} Visitor(*this);
|
|
if (!Visitor.TraverseStmt(Body))
|
|
return StmtError();
|
|
|
|
CXXExpansionStmt *Expansion = cast<CXXExpansionStmt>(Heading);
|
|
Expansion->setBody(Body);
|
|
|
|
if (Expansion->hasDependentSize())
|
|
return Expansion;
|
|
|
|
// Return an empty statement if the range is empty.
|
|
if (Expansion->getNumInstantiations() == 0)
|
|
return Expansion;
|
|
|
|
// Create a compound statement binding loop and body.
|
|
Stmt *VarAndBody[] = {Expansion->getExpansionVarStmt(), Body};
|
|
Stmt *CombinedBody = CompoundStmt::Create(Context, VarAndBody,
|
|
FPOptionsOverride(),
|
|
Expansion->getBeginLoc(),
|
|
Expansion->getEndLoc());
|
|
|
|
ExpansionStmtDecl *StmtDecl = cast<ExpansionStmtDecl>(CurContext);
|
|
DeclContext *DC = CurContext;
|
|
while (isa<ExpansionStmtDecl>(DC))
|
|
DC = DC->getParent();
|
|
|
|
// Expand the body for each instantiation.
|
|
SmallVector<Stmt *, 4> Instantiations;
|
|
while (Instantiations.size() < Expansion->getNumInstantiations()) {
|
|
ContextRAII CtxGuard(*this, DC, /*NewThis=*/false);
|
|
|
|
TemplateArgument TArgs[] = {
|
|
{ Context, llvm::APSInt::get(Instantiations.size()),
|
|
Context.getSizeType() }
|
|
};
|
|
MultiLevelTemplateArgumentList MTArgList(StmtDecl, TArgs, true);
|
|
MTArgList.addOuterRetainedLevels(
|
|
ExtractParmVarDeclDepth(Expansion->getTParamRef()));
|
|
|
|
LocalInstantiationScope LIScope(*this, /*CombineWithOuterScope=*/true);
|
|
InstantiatingTemplate Inst(*this, Body->getBeginLoc(), Expansion, TArgs,
|
|
Body->getSourceRange());
|
|
|
|
StmtResult Instantiation = SubstStmt(CombinedBody, MTArgList);
|
|
|
|
if (Instantiation.isInvalid())
|
|
return StmtError();
|
|
Instantiations.push_back(Instantiation.get());
|
|
}
|
|
|
|
// Allocate a more permanent buffer to hold pointers to Stmts.
|
|
Stmt **StmtStorage = new (Context) Stmt *[Instantiations.size()];
|
|
std::memcpy(StmtStorage, Instantiations.data(),
|
|
Instantiations.size() * sizeof(Stmt *));
|
|
|
|
// Attach Stmt buffer to the CXXExpansionStmt, and return.
|
|
Expansion->setInstantiations(StmtStorage);
|
|
return Expansion;
|
|
}
|
|
|
|
ExprResult Sema::ActOnCXXExpansionInitList(SourceLocation LBraceLoc,
|
|
MultiExprArg SubExprs,
|
|
SourceLocation RBraceLoc) {
|
|
return BuildCXXExpansionInitList(LBraceLoc, SubExprs, RBraceLoc);
|
|
}
|
|
|
|
ExprResult Sema::BuildCXXExpansionInitList(SourceLocation LBraceLoc,
|
|
MultiExprArg SubExprs,
|
|
SourceLocation RBraceLoc) {
|
|
Expr **SubExprList = new (Context) Expr *[SubExprs.size()];
|
|
std::memcpy(SubExprList, SubExprs.data(), SubExprs.size() * sizeof(Expr *));
|
|
|
|
return CXXExpansionInitListExpr::Create(Context, SubExprList,
|
|
SubExprs.size(), LBraceLoc,
|
|
RBraceLoc);
|
|
}
|
|
|
|
Decl *Sema::ActOnExpansionStmtDeclaration(Scope *S, unsigned TParamDepth,
|
|
SourceLocation TemplateKWLoc) {
|
|
// Compute how many layers of template parameters wrap this statement.
|
|
unsigned TemplateDepth = TParamDepth;
|
|
|
|
// Create a template parameter '__N'.
|
|
IdentifierInfo *ParmName = &Context.Idents.get("__N");
|
|
QualType ParmTy = Context.getSizeType();
|
|
TypeSourceInfo *ParmTI = Context.getTrivialTypeSourceInfo(ParmTy,
|
|
TemplateKWLoc);
|
|
|
|
NonTypeTemplateParmDecl *TParam =
|
|
NonTypeTemplateParmDecl::Create(Context,
|
|
Context.getTranslationUnitDecl(),
|
|
TemplateKWLoc, TemplateKWLoc,
|
|
TemplateDepth, /*Position=*/0, ParmName,
|
|
ParmTy, false, ParmTI);
|
|
|
|
return BuildExpansionStmtDeclaration(TemplateKWLoc, TParam);
|
|
}
|
|
|
|
Decl *Sema::BuildExpansionStmtDeclaration(SourceLocation TemplateKWLoc,
|
|
NonTypeTemplateParmDecl *NTTP) {
|
|
TemplateParameterList *TParamList =
|
|
TemplateParameterList::Create(Context, TemplateKWLoc, TemplateKWLoc,
|
|
{NTTP}, TemplateKWLoc, nullptr);
|
|
|
|
Decl *Result = ExpansionStmtDecl::Create(Context, CurContext, TemplateKWLoc,
|
|
nullptr, TParamList);
|
|
|
|
CurContext->addDecl(Result);
|
|
return Result;
|
|
}
|