summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclCXX.h4
-rw-r--r--include/clang/Sema/Initialization.h14
-rw-r--r--lib/AST/DeclCXX.cpp13
-rw-r--r--lib/AST/ExprConstant.cpp121
-rw-r--r--lib/Sema/SemaDeclCXX.cpp25
5 files changed, 80 insertions, 97 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 5a692e97ce..2071c1b0e1 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -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).
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index b2f1d558b1..b26bd7c917 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -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.
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 54fd723d97..7e85619c81 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -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,
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8fe27a515b..107913ed61 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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;
-
- 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;
- }
+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;
- if (InitE->isValueDependent())
- return false;
+ LValue Result;
+ Result.set(VD, Info.CurrentCall->Index);
+ APValue &Val = Info.CurrentCall->createTemporary(VD, true);
- if (!EvaluateInPlace(Val, Info, Result, InitE)) {
- // Wipe out any partially-computed value, to allow tracking that this
- // evaluation failed.
- 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;
+ }
- // 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);
+ if (InitE->isValueDependent())
+ return false;
- 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.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 41fcffd8cc..6193cd0eac 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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;
-
- InitializedEntity Entity = InitializedEntity::InitializeBinding(B, RefType);
+ 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(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++;