Author: rsmith Date: Sun Aug 14 18:15:52 2016 New Revision: 278640 URL: http://llvm.org/viewvc/llvm-project?rev=278640&view=rev Log: 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).
Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/Sema/Initialization.h cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=278640&r1=278639&r2=278640&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Sun Aug 14 18:15:52 2016 @@ -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). Modified: cfe/trunk/include/clang/Sema/Initialization.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=278640&r1=278639&r2=278640&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Initialization.h (original) +++ cfe/trunk/include/clang/Sema/Initialization.h Sun Aug 14 18:15:52 2016 @@ -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. Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=278640&r1=278639&r2=278640&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Aug 14 18:15:52 2016 @@ -2317,6 +2317,19 @@ BindingDecl *BindingDecl::CreateDeserial 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, Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=278640&r1=278639&r2=278640&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Aug 14 18:15:52 2016 @@ -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; - } - - if (InitE->isValueDependent()) - 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 (!EvaluateInPlace(Val, Info, Result, InitE)) { - // Wipe out any partially-computed value, to allow tracking that this - // evaluation failed. - Val = APValue(); - return false; - } + LValue Result; + Result.set(VD, Info.CurrentCall->Index); + APValue &Val = Info.CurrentCall->createTemporary(VD, true); + + 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::VisitDeclRefEx 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(c 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. Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278640&r1=278639&r2=278640&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Aug 14 18:15:52 2016 @@ -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( 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++; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits