[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