[cfe-commits] r143463 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Matthieu Monrocq matthieu.monrocq at gmail.com
Tue Nov 1 10:41:29 PDT 2011


Le 1 novembre 2011 17:57, Richard Smith <richard-llvm at metafoo.co.uk> a
écrit :

> Author: rsmith
> Date: Tue Nov  1 11:57:24 2011
> New Revision: 143463
>
> URL: http://llvm.org/viewvc/llvm-project?rev=143463&view=rev
> Log:
> Implement C++11 'constexpr calls must return constant expressions' rule,
> and
> perform the code simplifications this rule allows.
>
> Modified:
>    cfe/trunk/lib/AST/ExprConstant.cpp
>    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143463&r1=143462&r2=143463&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Nov  1 11:57:24 2011
> @@ -28,8 +28,6 @@
>  using llvm::APSInt;
>  using llvm::APFloat;
>
> -static bool IsParamLValue(const Expr *E);
> -
>  /// EvalInfo - This is a private struct used by the evaluator to capture
>  /// information about a subexpression as it is folded.  It retains
> information
>  /// about the AST context, but also maintains information about the folded
> @@ -53,27 +51,27 @@
>   class CCValue : public APValue {
>     typedef llvm::APSInt APSInt;
>     typedef llvm::APFloat APFloat;
> -    /// If the value is a DeclRefExpr lvalue referring to a ParmVarDecl,
> this is
> -    /// the index of the corresponding function call.
> -    unsigned CallIndex;
> +    /// If the value is a reference or pointer into a parameter or
> temporary,
> +    /// this is the corresponding call stack frame.
> +    CallStackFrame *CallFrame;
>   public:
> +    struct GlobalValue {};
> +
>     CCValue() {}
>     explicit CCValue(const APSInt &I) : APValue(I) {}
>     explicit CCValue(const APFloat &F) : APValue(F) {}
>     CCValue(const APValue *E, unsigned N) : APValue(E, N) {}
>     CCValue(const APSInt &R, const APSInt &I) : APValue(R, I) {}
>     CCValue(const APFloat &R, const APFloat &I) : APValue(R, I) {}
> -    CCValue(const CCValue &V) : APValue(V), CallIndex(V.CallIndex) {}
> -    CCValue(const Expr *B, const CharUnits &O, unsigned I) :
> -      APValue(B, O), CallIndex(I) {}
> -    CCValue(const APValue &V, unsigned CallIndex) :
> -      APValue(V), CallIndex(CallIndex) {}
> -
> -    enum { NoCallIndex = (unsigned)0 };
> +    CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {}
> +    CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F) :
> +      APValue(B, O), CallFrame(F) {}
> +    CCValue(const APValue &V, GlobalValue) :
> +      APValue(V), CallFrame(0) {}
>
> -    unsigned getLValueCallIndex() const {
> +    CallStackFrame *getLValueFrame() const {
>       assert(getKind() == LValue);
> -      return CallIndex;
> +      return CallFrame;
>     }
>   };
>
> @@ -88,11 +86,6 @@
>     /// parameters' function scope indices.
>     const CCValue *Arguments;
>
> -    /// CallIndex - The index of the current call. This is used to match
> lvalues
> -    /// referring to parameters up with the corresponding stack frame,
> and to
> -    /// detect when the parameter is no longer in scope.
> -    unsigned CallIndex;
> -
>     typedef llvm::DenseMap<const Expr*, CCValue> MapTy;
>     typedef MapTy::const_iterator temp_iterator;
>     /// Temporaries - Temporary lvalues materialized within this stack
> frame.
> @@ -131,10 +124,6 @@
>       : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0),
> CallStackDepth(0),
>         BottomFrame(*this, 0) {}
>
> -    unsigned getCurrentCallIndex() const { return CurrentCall->CallIndex;
> }
> -    CallStackFrame *getStackFrame(unsigned CallIndex) const;
> -    const CCValue *getCallValue(unsigned CallIndex, unsigned ArgIndex)
> const;
> -
>     const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
>       MapTy::const_iterator i = OpaqueValues.find(e);
>       if (i == OpaqueValues.end()) return 0;
> @@ -145,8 +134,7 @@
>   };
>
>   CallStackFrame::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
> -      : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
> -        CallIndex(Info.NumCalls++) {
> +      : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments) {
>     Info.CurrentCall = this;
>     ++Info.CallStackDepth;
>   }
> @@ -157,23 +145,6 @@
>     Info.CurrentCall = Caller;
>   }
>
> -  CallStackFrame *EvalInfo::getStackFrame(unsigned CallIndex) const {
> -    for (CallStackFrame *Frame = CurrentCall;
> -         Frame && Frame->CallIndex >= CallIndex; Frame = Frame->Caller)
> -      if (Frame->CallIndex == CallIndex)
> -        return Frame;
> -    return 0;
> -  }
> -
> -  const CCValue *EvalInfo::getCallValue(unsigned CallIndex,
> -                                        unsigned ArgIndex) const {
> -    if (CallIndex == 0)
> -      return 0;
> -    if (CallStackFrame *Frame = getStackFrame(CallIndex))
> -      return Frame->Arguments + ArgIndex;
> -    return 0;
> -  }
> -
>   struct ComplexValue {
>   private:
>     bool IsInt;
> @@ -217,21 +188,21 @@
>   struct LValue {
>     const Expr *Base;
>     CharUnits Offset;
> -    unsigned CallIndex;
> +    CallStackFrame *Frame;
>
>     const Expr *getLValueBase() const { return Base; }
>     CharUnits &getLValueOffset() { return Offset; }
>     const CharUnits &getLValueOffset() const { return Offset; }
> -    unsigned getLValueCallIndex() const { return CallIndex; }
> +    CallStackFrame *getLValueFrame() const { return Frame; }
>
>     void moveInto(CCValue &V) const {
> -      V = CCValue(Base, Offset, CallIndex);
> +      V = CCValue(Base, Offset, Frame);
>     }
>     void setFrom(const CCValue &V) {
>       assert(V.isLValue());
>       Base = V.getLValueBase();
>       Offset = V.getLValueOffset();
> -      CallIndex = V.getLValueCallIndex();
> +      Frame = V.getLValueFrame();
>     }
>   };
>  }
> @@ -269,12 +240,6 @@
>   return true;
>  }
>
> -static bool IsParamLValue(const Expr *E) {
> -  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
> -    return isa<ParmVarDecl>(DRE->getDecl());
> -  return false;
> -}
> -
>  /// Check that this core constant expression value is a valid value for a
>  /// constant expression.
>  static bool CheckConstantExpression(const CCValue &Value) {
> @@ -419,16 +384,14 @@
>
>  /// Try to evaluate the initializer for a variable declaration.
>  static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,
> -                                unsigned CallIndex, CCValue &Result) {
> +                                CallStackFrame *Frame, CCValue &Result) {
>   // If this is a parameter to an active constexpr function call, perform
>   // argument substitution.
>   if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
> -    if (const CCValue *ArgValue =
> -          Info.getCallValue(CallIndex, PVD->getFunctionScopeIndex())) {
> -      Result = *ArgValue;
> -      return true;
> -    }
> -    return false;
> +    if (!Frame || !Frame->Arguments)
> +      return false;
> +    Result = Frame->Arguments[PVD->getFunctionScopeIndex()];
> +    return true;
>   }
>
>   const Expr *Init = VD->getAnyInitializer();
> @@ -436,7 +399,7 @@
>     return false;
>
>   if (APValue *V = VD->getEvaluatedValue()) {
> -    Result = CCValue(*V, CCValue::NoCallIndex);
> +    Result = CCValue(*V, CCValue::GlobalValue());
>     return !Result.isUninit();
>   }
>
> @@ -466,7 +429,7 @@
>  bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
>                                     const LValue &LVal, CCValue &RVal) {
>   const Expr *Base = LVal.Base;
> -  unsigned CallIndex = LVal.CallIndex;
> +  CallStackFrame *Frame = LVal.Frame;
>
>   // FIXME: Indirection through a null pointer deserves a diagnostic.
>   if (!Base)
> @@ -498,8 +461,7 @@
>     // them are not permitted.
>     const VarDecl *VD = dyn_cast<VarDecl>(D);
>     if (!VD || !(IsConstNonVolatile(VD->getType()) ||
> isa<ParmVarDecl>(VD)) ||
> -        !Type->isLiteralType() ||
> -        !EvaluateVarDeclInit(Info, VD, CallIndex, RVal))
> +        !Type->isLiteralType() || !EvaluateVarDeclInit(Info, VD, Frame,
> RVal))
>       return false;
>
>     if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
> @@ -513,17 +475,14 @@
>     if (!RVal.getLValueOffset().isZero())
>       return false;
>     Base = RVal.getLValueBase();
> -    CallIndex = RVal.getLValueCallIndex();
> +    Frame = RVal.getLValueFrame();
>   }
>
> -  // If this is an lvalue expression with a nontrivial initializer, grab
> the
> -  // value from the relevant stack frame, if the object is still in scope.
> -  if (isa<MaterializeTemporaryExpr>(Base)) {
> -    if (CallStackFrame *Frame = Info.getStackFrame(CallIndex)) {
> -      RVal = Frame->Temporaries[Base];
> -      return true;
> -    }
> -    return false;
> +  // If this is a temporary expression with a nontrivial initializer,
> grab the
> +  // value from the relevant stack frame.
> +  if (Frame) {
> +    RVal = Frame->Temporaries[Base];
> +    return true;
>   }
>
>   // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating
> the
> @@ -726,6 +685,14 @@
>
>   RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }
>
> +  bool MakeTemporary(const Expr *Key, const Expr *Value, LValue &Result) {
> +    if (!Evaluate(Info.CurrentCall->Temporaries[Key], Info, Value))
> +      return false;
> +    Result.Base = Key;
> +    Result.Offset = CharUnits::Zero();
> +    Result.Frame = Info.CurrentCall;
> +    return true;
> +  }
>  public:
>   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
>
> @@ -813,7 +780,8 @@
>     llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
>
>     if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl()
> &&
> -        HandleFunctionCall(Args, Body, Info, Result))
> +        HandleFunctionCall(Args, Body, Info, Result) &&
> +        CheckConstantExpression(Result))
>       return DerivedSuccess(Result, E);
>
>     return DerivedError(E);
> @@ -881,7 +849,6 @@
>  // following types:
>  //  * DeclRefExpr
>  //  * MemberExpr for a static member
> -//  * MaterializeTemporaryExpr
>  //  * CompoundLiteralExpr in C
>  //  * StringLiteral
>  //  * PredefinedExpr
> @@ -889,7 +856,9 @@
>  //  * AddrLabelExpr
>  //  * BlockExpr
>  //  * CallExpr for a MakeStringConstant builtin
> -// plus an offset in bytes.
> +// plus an offset in bytes. It can also produce lvalues referring to
> locals. In
> +// that case, the Frame will point to a stack frame, and the Expr is used
> as a
> +// key to find the relevant temporary's value.
>
>  //===----------------------------------------------------------------------===//
>  namespace {
>  class LValueExprEvaluator
> @@ -900,7 +869,7 @@
>   bool Success(const Expr *E) {
>     Result.Base = E;
>     Result.Offset = CharUnits::Zero();
> -    Result.CallIndex = Info.getCurrentCallIndex();
> +    Result.Frame = 0;
>     return true;
>   }
>  public:
> @@ -967,11 +936,18 @@
>  }
>
>  bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
> -  if (!VD->getType()->isReferenceType())
> +  if (!VD->getType()->isReferenceType()) {
> +    if (isa<ParmVarDecl>(VD)) {
> +      Result.Base = E;
> +      Result.Offset = CharUnits::Zero();
> +      Result.Frame = Info.CurrentCall;
> +      return true;
> +    }
>     return Success(E);
> +  }
>
>   CCValue V;
> -  if (EvaluateVarDeclInit(Info, VD, Info.getCurrentCallIndex(), V))
> +  if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V))
>     return Success(V, E);
>
>   return Error(E);
> @@ -979,9 +955,7 @@
>
>  bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
>     const MaterializeTemporaryExpr *E) {
> -  if (!Evaluate(Info.CurrentCall->Temporaries[E], Info,
> E->GetTemporaryExpr()))
> -    return false;
> -  return Success(E);
> +  return MakeTemporary(E, E->GetTemporaryExpr(), Result);
>  }
>
>  bool
> @@ -1066,7 +1040,7 @@
>   bool Success(const Expr *E) {
>     Result.Base = E;
>     Result.Offset = CharUnits::Zero();
> -    Result.CallIndex = Info.getCurrentCallIndex();
> +    Result.Frame = 0;
>     return true;
>   }
>  public:
> @@ -1213,7 +1187,7 @@
>       uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
>       Result.Base = 0;
>       Result.Offset = CharUnits::fromQuantity(N);
> -      Result.CallIndex = CCValue::NoCallIndex;
> +      Result.Frame = 0;
>       return true;
>     } else {
>       // Cast is of an lvalue, no need to change value.
> @@ -1839,7 +1813,7 @@
>   }
>
>   return IsGlobalLValue(A.getLValueBase()) ||
> -         A.getLValueCallIndex() == B.getLValueCallIndex();
> +         A.getLValueFrame() == B.getLValueFrame();
>  }
>
>  bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
> @@ -3124,7 +3098,7 @@
>                                       const ASTContext &Ctx) const {
>   EvalResult Scratch;
>   return EvaluateAsRValue(Scratch, Ctx) &&
> -         HandleConversionToBool(CCValue(Scratch.Val,
> CCValue::NoCallIndex),
> +         HandleConversionToBool(CCValue(Scratch.Val,
> CCValue::GlobalValue()),
>                                 Result);
>  }
>
> @@ -3155,9 +3129,7 @@
>   EvalInfo Info(Ctx, Result);
>
>   LValue LV;
> -  // Don't allow references to out-of-scope function parameters to escape.
> -  if (EvaluateLValue(this, LV, Info) &&
> -      (!IsParamLValue(LV.Base) || LV.CallIndex == CCValue::NoCallIndex)) {
> +  if (EvaluateLValue(this, LV, Info)) {
>     Result.Val = APValue(LV.Base, LV.Offset);
>     return true;
>   }
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143463&r1=143462&r2=143463&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Nov  1
> 11:57:24 2011
> @@ -102,6 +102,14 @@
>   constexpr int n1 = MaybeReturnJunk(false, 0); // ok
>   constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be
> initialized by a constant expression}}
>
> +  constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
> +    // If ObscureTheTruth returns a reference to 'a', the result is not a
> +    // constant expression even though 'a' is still in scope.
> +    return ObscureTheTruth(b ? a : k);
> +  }
> +  constexpr int n1a = MaybeReturnJunk(false, 0); // ok
> +  constexpr int n2a = MaybeReturnJunk(true, 0); // expected-error {{must
> be initialized by a constant expression}}
> +
>

Is it your intention to use  MaybeReturnJunk   and not the newly introduced
  MaybeReturnNonstaticRef   here ?


>   constexpr int InternalReturnJunk(int n) {
>     // FIXME: We should reject this: it never produces a constant
> expression.
>     return MaybeReturnJunk(true, n);
>
>
--Matthieu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20111101/87c02ff0/attachment.html>


More information about the cfe-commits mailing list