forked from OSchip/llvm-project
Explicitly generate a reference variable to hold the initializer for a
tuple-like decomposition declaration. This significantly simplifies the semantics of BindingDecls for AST consumers (they can now always be evalated at the point of use). llvm-svn: 278640
This commit is contained in:
parent
52fe9ae990
commit
97fcf4be9b
|
@ -3404,6 +3404,10 @@ public:
|
|||
/// decomposition declaration, and when the initializer is type-dependent.
|
||||
Expr *getBinding() const { return Binding; }
|
||||
|
||||
/// Get the variable (if any) that holds the value of evaluating the binding.
|
||||
/// Only present for user-defined bindings for tuple-like types.
|
||||
VarDecl *getHoldingVar() const;
|
||||
|
||||
/// Set the binding for this BindingDecl, along with its declared type (which
|
||||
/// should be a possibly-cv-qualified form of the type of the binding, or a
|
||||
/// reference to such a type).
|
||||
|
|
|
@ -163,8 +163,8 @@ private:
|
|||
InitializedEntity() : ManglingNumber(0) {}
|
||||
|
||||
/// \brief Create the initialization entity for a variable.
|
||||
InitializedEntity(VarDecl *Var)
|
||||
: Kind(EK_Variable), Parent(nullptr), Type(Var->getType()),
|
||||
InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
|
||||
: Kind(EK), Parent(nullptr), Type(Var->getType()),
|
||||
ManglingNumber(0), VariableOrMember(Var) { }
|
||||
|
||||
/// \brief Create the initialization entity for the result of a
|
||||
|
@ -183,11 +183,6 @@ private:
|
|||
: Kind(EK_Member), Parent(Parent), Type(Member->getType()),
|
||||
ManglingNumber(0), VariableOrMember(Member) { }
|
||||
|
||||
/// \brief Create the initialization entity for a binding.
|
||||
InitializedEntity(BindingDecl *Binding, QualType Type)
|
||||
: Kind(EK_Binding), Parent(nullptr), Type(Type),
|
||||
ManglingNumber(0), VariableOrMember(Binding) {}
|
||||
|
||||
/// \brief Create the initialization entity for an array element.
|
||||
InitializedEntity(ASTContext &Context, unsigned Index,
|
||||
const InitializedEntity &Parent);
|
||||
|
@ -323,9 +318,8 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Create the initialization entity for a structured binding.
|
||||
static InitializedEntity InitializeBinding(BindingDecl *Binding,
|
||||
QualType Type) {
|
||||
return InitializedEntity(Binding, Type);
|
||||
static InitializedEntity InitializeBinding(VarDecl *Binding) {
|
||||
return InitializedEntity(Binding, EK_Binding);
|
||||
}
|
||||
|
||||
/// \brief Create the initialization entity for a lambda capture.
|
||||
|
|
|
@ -2317,6 +2317,19 @@ BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
|||
return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr);
|
||||
}
|
||||
|
||||
VarDecl *BindingDecl::getHoldingVar() const {
|
||||
Expr *B = getBinding();
|
||||
if (!B)
|
||||
return nullptr;
|
||||
auto *DRE = dyn_cast<DeclRefExpr>(B->IgnoreImplicit());
|
||||
if (!DRE)
|
||||
return nullptr;
|
||||
|
||||
auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
|
||||
assert(VD->isImplicit() && "holding var for binding decl not implicit");
|
||||
return VD;
|
||||
}
|
||||
|
||||
void DecompositionDecl::anchor() {}
|
||||
|
||||
DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
|
|
|
@ -3400,50 +3400,51 @@ enum EvalStmtResult {
|
|||
};
|
||||
}
|
||||
|
||||
static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
// We don't need to evaluate the initializer for a static local.
|
||||
if (!VD->hasLocalStorage())
|
||||
return true;
|
||||
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
|
||||
// We don't need to evaluate the initializer for a static local.
|
||||
if (!VD->hasLocalStorage())
|
||||
return true;
|
||||
|
||||
LValue Result;
|
||||
Result.set(VD, Info.CurrentCall->Index);
|
||||
APValue &Val = Info.CurrentCall->createTemporary(VD, true);
|
||||
LValue Result;
|
||||
Result.set(VD, Info.CurrentCall->Index);
|
||||
APValue &Val = Info.CurrentCall->createTemporary(VD, true);
|
||||
|
||||
const Expr *InitE = VD->getInit();
|
||||
if (!InitE) {
|
||||
Info.FFDiag(D->getLocStart(), diag::note_constexpr_uninitialized)
|
||||
<< false << VD->getType();
|
||||
Val = APValue();
|
||||
return false;
|
||||
}
|
||||
const Expr *InitE = VD->getInit();
|
||||
if (!InitE) {
|
||||
Info.FFDiag(VD->getLocStart(), diag::note_constexpr_uninitialized)
|
||||
<< false << VD->getType();
|
||||
Val = APValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InitE->isValueDependent())
|
||||
return false;
|
||||
if (InitE->isValueDependent())
|
||||
return false;
|
||||
|
||||
if (!EvaluateInPlace(Val, Info, Result, InitE)) {
|
||||
// Wipe out any partially-computed value, to allow tracking that this
|
||||
// evaluation failed.
|
||||
Val = APValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate initializers for any structured bindings.
|
||||
if (auto *DD = dyn_cast<DecompositionDecl>(VD)) {
|
||||
for (auto *BD : DD->bindings()) {
|
||||
APValue &Val = Info.CurrentCall->createTemporary(BD, true);
|
||||
|
||||
LValue Result;
|
||||
if (!EvaluateLValue(BD->getBinding(), Result, Info))
|
||||
return false;
|
||||
Result.moveInto(Val);
|
||||
}
|
||||
}
|
||||
if (!EvaluateInPlace(Val, Info, Result, InitE)) {
|
||||
// Wipe out any partially-computed value, to allow tracking that this
|
||||
// evaluation failed.
|
||||
Val = APValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
|
||||
bool OK = true;
|
||||
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
OK &= EvaluateVarDecl(Info, VD);
|
||||
|
||||
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D))
|
||||
for (auto *BD : DD->bindings())
|
||||
if (auto *VD = BD->getHoldingVar())
|
||||
OK &= EvaluateDecl(Info, VD);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/// Evaluate a condition (either a variable declaration or an expression).
|
||||
static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
|
||||
const Expr *Cond, bool &Result) {
|
||||
|
@ -4736,7 +4737,6 @@ public:
|
|||
LValueExprEvaluatorBaseTy(Info, Result) {}
|
||||
|
||||
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
|
||||
bool VisitBindingDecl(const Expr *E, const BindingDecl *BD);
|
||||
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
|
||||
|
||||
bool VisitDeclRefExpr(const DeclRefExpr *E);
|
||||
|
@ -4799,7 +4799,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
|
|||
if (const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
|
||||
return VisitVarDecl(E, VD);
|
||||
if (const BindingDecl *BD = dyn_cast<BindingDecl>(E->getDecl()))
|
||||
return VisitBindingDecl(E, BD);
|
||||
return Visit(BD->getBinding());
|
||||
return Error(E);
|
||||
}
|
||||
|
||||
|
@ -4827,53 +4827,6 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
|
|||
return Success(*V, E);
|
||||
}
|
||||
|
||||
bool LValueExprEvaluator::VisitBindingDecl(const Expr *E,
|
||||
const BindingDecl *BD) {
|
||||
// If we've already evaluated the binding, just return the lvalue.
|
||||
if (APValue *Value = Info.CurrentCall->getTemporary(BD)) {
|
||||
if (Value->isUninit()) {
|
||||
if (!Info.checkingPotentialConstantExpression())
|
||||
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
|
||||
return false;
|
||||
}
|
||||
return Success(*Value, E);
|
||||
}
|
||||
|
||||
// We've not evaluated the initializer of this binding. It's still OK if it
|
||||
// is initialized by a constant expression.
|
||||
//
|
||||
// FIXME: We should check this at the point of declaration, since we're not
|
||||
// supposed to be able to use it if it references something that was declared
|
||||
// later.
|
||||
auto *Binding = BD->getBinding();
|
||||
if (!Binding) {
|
||||
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Evaluate in an independent context to check whether the binding was a
|
||||
// constant expression in an absolute sense, and without mutating any of
|
||||
// our local state.
|
||||
Expr::EvalStatus InitStatus;
|
||||
SmallVector<PartialDiagnosticAt, 8> Diag;
|
||||
InitStatus.Diag = &Diag;
|
||||
EvalInfo InitInfo(Info.Ctx, InitStatus, EvalInfo::EM_ConstantExpression);
|
||||
|
||||
if (!EvaluateLValue(Binding, Result, InitInfo) || InitStatus.HasSideEffects ||
|
||||
!CheckLValueConstantExpression(
|
||||
InitInfo, Binding->getExprLoc(),
|
||||
Info.Ctx.getLValueReferenceType(BD->getType()), Result) ||
|
||||
!Diag.empty()) {
|
||||
// FIXME: Diagnose this better. Maybe produce the Diags to explain why
|
||||
// the initializer was not constant.
|
||||
if (!Info.checkingPotentialConstantExpression())
|
||||
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
|
||||
const MaterializeTemporaryExpr *E) {
|
||||
// Walk through the expression to find the materialized temporary itself.
|
||||
|
|
|
@ -1067,7 +1067,7 @@ struct BindingDiagnosticTrap {
|
|||
|
||||
static bool checkTupleLikeDecomposition(Sema &S,
|
||||
ArrayRef<BindingDecl *> Bindings,
|
||||
ValueDecl *Src, QualType DecompType,
|
||||
VarDecl *Src, QualType DecompType,
|
||||
llvm::APSInt TupleSize) {
|
||||
if ((int64_t)Bindings.size() != TupleSize) {
|
||||
S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
|
||||
|
@ -1151,13 +1151,32 @@ static bool checkTupleLikeDecomposition(Sema &S,
|
|||
S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName());
|
||||
if (RefType.isNull())
|
||||
return true;
|
||||
auto *RefVD = VarDecl::Create(
|
||||
S.Context, Src->getDeclContext(), Loc, Loc,
|
||||
B->getDeclName().getAsIdentifierInfo(), RefType,
|
||||
S.Context.getTrivialTypeSourceInfo(T, Loc), Src->getStorageClass());
|
||||
RefVD->setLexicalDeclContext(Src->getLexicalDeclContext());
|
||||
RefVD->setTSCSpec(Src->getTSCSpec());
|
||||
RefVD->setImplicit();
|
||||
if (Src->isInlineSpecified())
|
||||
RefVD->setInlineSpecified();
|
||||
|
||||
InitializedEntity Entity = InitializedEntity::InitializeBinding(B, RefType);
|
||||
InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD);
|
||||
InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc);
|
||||
InitializationSequence Seq(S, Entity, Kind, Init);
|
||||
E = Seq.Perform(S, Entity, Kind, Init);
|
||||
if (E.isInvalid())
|
||||
return true;
|
||||
RefVD->setInit(E.get());
|
||||
RefVD->checkInitIsICE();
|
||||
|
||||
RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD);
|
||||
|
||||
E = S.BuildDeclarationNameExpr(CXXScopeSpec(),
|
||||
DeclarationNameInfo(B->getDeclName(), Loc),
|
||||
RefVD);
|
||||
if (E.isInvalid())
|
||||
return true;
|
||||
|
||||
B->setBinding(T, E.get());
|
||||
I++;
|
||||
|
|
Loading…
Reference in New Issue