Le 1 novembre 2011 17:57, Richard Smith <[email protected]> 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
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
