summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp62
1 files changed, 62 insertions, 0 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 176f1ba8422..8fe27a515bb 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3427,6 +3427,18 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
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);
+ }
+ }
}
return true;
@@ -4724,6 +4736,7 @@ 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);
@@ -4785,6 +4798,8 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
return Success(FD);
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 Error(E);
}
@@ -4812,6 +4827,53 @@ 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.
OpenPOWER on IntegriCloud