r278640 - Explicitly generate a reference variable to hold the initializer for a

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 14 16:15:52 PDT 2016


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++;




More information about the cfe-commits mailing list