diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 375af28f0c56e52fa14e88d14bba3e0935e3d28e..525d88cab2a19280358f2bf156a195e6d8a8837d 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -170,7 +170,10 @@ public: } const Expr* getLValueBase() const; - CharUnits getLValueOffset() const; + CharUnits &getLValueOffset(); + const CharUnits &getLValueOffset() const { + return const_cast(this)->getLValueOffset(); + } void setInt(const APSInt &I) { assert(isInt() && "Invalid accessor"); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 6f63a32dd2ed38999a4d38288cab3558a2c15ac0..0f315bbccda20fd908090788df3cf5266b58648a 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -169,9 +169,9 @@ const Expr* APValue::getLValueBase() const { return ((const LV*)(const void*)Data)->Base; } -CharUnits APValue::getLValueOffset() const { - assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data)->Offset; +CharUnits &APValue::getLValueOffset() { + assert(isLValue() && "Invalid accessor"); + return ((LV*)(void*)Data)->Offset; } void APValue::setLValue(const Expr *B, const CharUnits &O) { @@ -185,4 +185,3 @@ void APValue::MakeLValue() { new ((void*)(char*)Data) LV(); Kind = LValue; } - diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index bba7d5e57903caab4a1d7a1f62325a2491541914..31fddb62485923458b160dc65af2bbfbba44d6ee 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -28,6 +28,8 @@ using namespace clang; 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 @@ -45,6 +47,35 @@ using llvm::APFloat; namespace { struct CallStackFrame; + /// A core constant value. This can be the value of any constant expression, + /// or a pointer or reference to a non-static object or function parameter. + 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; + public: + 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)-1 }; + + unsigned getLValueCallIndex() const { + assert(getKind() == LValue); + return CallIndex; + } + }; + struct EvalInfo { const ASTContext &Ctx; @@ -60,14 +91,17 @@ namespace { /// CallStackDepth - The number of calls in the call stack right now. unsigned CallStackDepth; - typedef llvm::DenseMap MapTy; + typedef llvm::DenseMap MapTy; MapTy OpaqueValues; - const APValue *getOpaqueValue(const OpaqueValueExpr *e) const { + const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const { MapTy::const_iterator i = OpaqueValues.find(e); if (i == OpaqueValues.end()) return 0; return &i->second; } + unsigned getCurrentCallIndex() const; + const CCValue *getCallValue(unsigned CallIndex, unsigned ArgIndex) const; + EvalInfo(const ASTContext &C, Expr::EvalStatus &S) : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0) {} @@ -83,14 +117,14 @@ namespace { /// ParmBindings - Parameter bindings for this function call, indexed by /// parameters' function scope indices. - const APValue *Arguments; + 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; - CallStackFrame(EvalInfo &Info, const APValue *Arguments) + CallStackFrame(EvalInfo &Info, const CCValue *Arguments) : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments), CallIndex(Info.NumCalls++) { Info.CurrentCall = this; @@ -103,6 +137,19 @@ namespace { } }; + unsigned EvalInfo::getCurrentCallIndex() const { + return CurrentCall ? CurrentCall->CallIndex : CCValue::NoCallIndex; + } + + const CCValue *EvalInfo::getCallValue(unsigned CallIndex, + unsigned ArgIndex) const { + for (const CallStackFrame *Frame = CurrentCall; + Frame && Frame->CallIndex >= CallIndex; Frame = Frame->Caller) + if (Frame->CallIndex == CallIndex) + return Frame->Arguments + ArgIndex; + return 0; + } + struct ComplexValue { private: bool IsInt; @@ -123,13 +170,13 @@ namespace { APSInt &getComplexIntReal() { return IntReal; } APSInt &getComplexIntImag() { return IntImag; } - void moveInto(APValue &v) const { + void moveInto(CCValue &v) const { if (isComplexFloat()) - v = APValue(FloatReal, FloatImag); + v = CCValue(FloatReal, FloatImag); else - v = APValue(IntReal, IntImag); + v = CCValue(IntReal, IntImag); } - void setFrom(const APValue &v) { + void setFrom(const CCValue &v) { assert(v.isComplexFloat() || v.isComplexInt()); if (v.isComplexFloat()) { makeComplexFloat(); @@ -146,26 +193,29 @@ namespace { struct LValue { const Expr *Base; CharUnits Offset; + unsigned CallIndex; const Expr *getLValueBase() { return Base; } - CharUnits getLValueOffset() { return Offset; } + CharUnits &getLValueOffset() { return Offset; } + unsigned getLValueCallIndex() { return CallIndex; } - void moveInto(APValue &v) const { - v = APValue(Base, Offset); + void moveInto(CCValue &V) const { + V = CCValue(Base, Offset, CallIndex); } - void setFrom(const APValue &v) { - assert(v.isLValue()); - Base = v.getLValueBase(); - Offset = v.getLValueOffset(); + void setFrom(const CCValue &V) { + assert(V.isLValue()); + Base = V.getLValueBase(); + Offset = V.getLValueOffset(); + CallIndex = V.getLValueCallIndex(); } }; } -static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); +static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); -static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, +static bool EvaluateIntegerOrLValue(const Expr *E, CCValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); @@ -194,6 +244,18 @@ static bool IsGlobalLValue(const Expr* E) { return true; } +static bool IsParamLValue(const Expr *E) { + if (const DeclRefExpr *DRE = dyn_cast_or_null(E)) + return isa(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) { + return !Value.isLValue() || IsGlobalLValue(Value.getLValueBase()); +} + static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { const Expr* Base = Value.Base; @@ -205,6 +267,7 @@ static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { } // Require the base expression to be a global l-value. + // FIXME: C++11 requires such conversions. Remove this check. if (!IsGlobalLValue(Base)) return false; // We have a non-null base expression. These are generally known to @@ -226,7 +289,7 @@ static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { return true; } -static bool HandleConversionToBool(const APValue &Val, bool &Result) { +static bool HandleConversionToBool(const CCValue &Val, bool &Result) { switch (Val.getKind()) { case APValue::Uninitialized: return false; @@ -244,12 +307,11 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) { Result = !Val.getComplexFloatReal().isZero() || !Val.getComplexFloatImag().isZero(); return true; - case APValue::LValue: - { - LValue PointerResult; - PointerResult.setFrom(Val); - return EvalPointerValueAsBool(PointerResult, Result); - } + case APValue::LValue: { + LValue PointerResult; + PointerResult.setFrom(Val); + return EvalPointerValueAsBool(PointerResult, Result); + } case APValue::Vector: return false; } @@ -260,7 +322,7 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) { static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, EvalInfo &Info) { assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition"); - APValue Val; + CCValue Val; if (!Evaluate(Val, Info, E)) return false; return HandleConversionToBool(Val, Result); @@ -309,40 +371,44 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, } /// Try to evaluate the initializer for a variable declaration. -static const APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) { +static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD, + unsigned CallIndex, CCValue &Result) { // If this is a parameter to an active constexpr function call, perform // argument substitution. if (const ParmVarDecl *PVD = dyn_cast(VD)) { - // FIXME This assumes that all parameters must be parameters of the current - // call. Add the CallIndex to the LValue representation and use that to - // check. - if (Info.CurrentCall) - return &Info.CurrentCall->Arguments[PVD->getFunctionScopeIndex()]; - return 0; + if (const CCValue *ArgValue = + Info.getCallValue(CallIndex, PVD->getFunctionScopeIndex())) { + Result = *ArgValue; + return true; + } + return false; } const Expr *Init = VD->getAnyInitializer(); if (!Init) - return 0; + return false; - if (APValue *V = VD->getEvaluatedValue()) - return V; + if (APValue *V = VD->getEvaluatedValue()) { + Result = CCValue(*V, CCValue::NoCallIndex); + return !Result.isUninit(); + } if (VD->isEvaluatingValue()) - return 0; + return false; VD->setEvaluatingValue(); - Expr::EvalResult EResult; - EvalInfo InitInfo(Info.Ctx, EResult); + Expr::EvalStatus EStatus; + EvalInfo InitInfo(Info.Ctx, EStatus); // FIXME: The caller will need to know whether the value was a constant // expression. If not, we should propagate up a diagnostic. - if (Evaluate(EResult.Val, InitInfo, Init)) - VD->setEvaluatedValue(EResult.Val); - else + if (!Evaluate(Result, InitInfo, Init) || !CheckConstantExpression(Result)) { VD->setEvaluatedValue(APValue()); + return false; + } - return VD->getEvaluatedValue(); + VD->setEvaluatedValue(Result); + return true; } static bool IsConstNonVolatile(QualType T) { @@ -351,7 +417,7 @@ static bool IsConstNonVolatile(QualType T) { } bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, - const LValue &LVal, APValue &RVal) { + const LValue &LVal, CCValue &RVal) { const Expr *Base = LVal.Base; // FIXME: Indirection through a null pointer deserves a diagnostic. @@ -401,26 +467,21 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, // them are not permitted. const VarDecl *VD = dyn_cast(D); if (!VD || !(IsConstNonVolatile(VD->getType()) || isa(VD)) || - !(Type->isIntegralOrEnumerationType() || Type->isRealFloatingType())) + !(Type->isIntegralOrEnumerationType() || Type->isRealFloatingType()) || + !EvaluateVarDeclInit(Info, VD, LVal.CallIndex, RVal)) return false; - const APValue *V = EvaluateVarDeclInit(Info, VD); - if (!V || V->isUninit()) - return false; - - if (isa(VD) || !VD->getAnyInitializer()->isLValue()) { - RVal = *V; + if (isa(VD) || !VD->getAnyInitializer()->isLValue()) return true; - } // The declaration was initialized by an lvalue, with no lvalue-to-rvalue // conversion. This happens when the declaration and the lvalue should be // considered synonymous, for instance when initializing an array of char // from a string literal. Continue as if the initializer lvalue was the // value we were originally given. - Base = V->getLValueBase(); - if (!V->getLValueOffset().isZero()) + if (!RVal.getLValueOffset().isZero()) return false; + Base = RVal.getLValueBase(); } // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and @@ -449,7 +510,7 @@ enum EvalStmtResult { } // Evaluate a statement. -static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info, const Stmt *S) { switch (S->getStmtClass()) { default: @@ -479,12 +540,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, /// Evaluate a function call. static bool HandleFunctionCall(ArrayRef Args, const Stmt *Body, - EvalInfo &Info, APValue &Result) { + EvalInfo &Info, CCValue &Result) { // FIXME: Implement a proper call limit, along with a command-line flag. if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512) return false; - SmallVector ArgValues(Args.size()); + SmallVector ArgValues(Args.size()); // FIXME: Deal with default arguments and 'this'. for (ArrayRef::iterator I = Args.begin(), E = Args.end(); I != E; ++I) @@ -609,7 +670,7 @@ template class ExprEvaluatorBase : public ConstStmtVisitor { private: - RetTy DerivedSuccess(const APValue &V, const Expr *E) { + RetTy DerivedSuccess(const CCValue &V, const Expr *E) { return static_cast(this)->Success(V, E); } RetTy DerivedError(const Expr *E) { @@ -671,11 +732,11 @@ public: } RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - const APValue *value = Info.getOpaqueValue(E); - if (!value) + const CCValue *Value = Info.getOpaqueValue(E); + if (!Value) return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr()) : DerivedError(E)); - return DerivedSuccess(*value, E); + return DerivedSuccess(*Value, E); } RetTy VisitCallExpr(const CallExpr *E) { @@ -690,7 +751,7 @@ public: if (!CalleeType->isFunctionType() && !CalleeType->isFunctionPointerType()) return DerivedError(E); - APValue Call; + CCValue Call; if (!Evaluate(Call, Info, Callee) || !Call.isLValue() || !Call.getLValueBase() || !Call.getLValueOffset().isZero()) return DerivedError(Callee); @@ -709,7 +770,7 @@ public: const FunctionDecl *Definition; Stmt *Body = FD->getBody(Definition); - APValue Result; + CCValue Result; llvm::ArrayRef Args(E->getArgs(), E->getNumArgs()); if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() && @@ -749,7 +810,7 @@ public: case CK_LValueToRValue: { LValue LVal; if (EvaluateLValue(E->getSubExpr(), LVal, Info)) { - APValue RVal; + CCValue RVal; if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal)) return DerivedSuccess(RVal, E); } @@ -762,7 +823,7 @@ public: /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { - APValue Scratch; + CCValue Scratch; if (!Evaluate(Scratch, Info, E)) Info.EvalStatus.HasSideEffects = true; } @@ -799,6 +860,7 @@ class LValueExprEvaluator bool Success(const Expr *E) { Result.Base = E; Result.Offset = CharUnits::Zero(); + Result.CallIndex = Info.getCurrentCallIndex(); return true; } public: @@ -806,7 +868,7 @@ public: LValueExprEvaluator(EvalInfo &info, LValue &Result) : ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {} - bool Success(const APValue &V, const Expr *E) { + bool Success(const CCValue &V, const Expr *E) { Result.setFrom(V); return true; } @@ -867,9 +929,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (!VD->getType()->isReferenceType()) return Success(E); - const APValue *V = EvaluateVarDeclInit(Info, VD); - if (V && !V->isUninit()) - return Success(*V, E); + CCValue V; + if (EvaluateVarDeclInit(Info, VD, Info.getCurrentCallIndex(), V)) + return Success(V, E); return Error(E); } @@ -956,6 +1018,7 @@ class PointerExprEvaluator bool Success(const Expr *E) { Result.Base = E; Result.Offset = CharUnits::Zero(); + Result.CallIndex = Info.getCurrentCallIndex(); return true; } public: @@ -963,7 +1026,7 @@ public: PointerExprEvaluator(EvalInfo &info, LValue &Result) : ExprEvaluatorBaseTy(info), Result(Result) {} - bool Success(const APValue &V, const Expr *E) { + bool Success(const CCValue &V, const Expr *E) { Result.setFrom(V); return true; } @@ -1059,8 +1122,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { - LValue BaseLV; - if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info)) + if (!EvaluatePointer(E->getSubExpr(), Result, Info)) return false; // Now figure out the necessary offset to add to the baseLV to get from @@ -1083,35 +1145,31 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); - Offset += Layout.getBaseClassOffset(BaseDecl); + Result.getLValueOffset() += Layout.getBaseClassOffset(BaseDecl); DerivedDecl = BaseDecl; } - Result.Base = BaseLV.getLValueBase(); - Result.Offset = BaseLV.getLValueOffset() + Offset; return true; } - case CK_NullToPointer: { - Result.Base = 0; - Result.Offset = CharUnits::Zero(); - return true; - } + case CK_NullToPointer: + return ValueInitialization(E); case CK_IntegralToPointer: { - APValue Value; + CCValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) break; if (Value.isInt()) { - Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + unsigned Size = Info.Ctx.getTypeSize(E->getType()); + uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue(); Result.Base = 0; - Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); + Result.Offset = CharUnits::fromQuantity(N); + Result.CallIndex = CCValue::NoCallIndex; return true; } else { // Cast is of an lvalue, no need to change value. - Result.Base = Value.getLValueBase(); - Result.Offset = Value.getLValueOffset(); + Result.setFrom(Value); return true; } } @@ -1331,9 +1389,9 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { namespace { class IntExprEvaluator : public ExprEvaluatorBase { - APValue &Result; + CCValue &Result; public: - IntExprEvaluator(EvalInfo &info, APValue &result) + IntExprEvaluator(EvalInfo &info, CCValue &result) : ExprEvaluatorBaseTy(info), Result(result) {} bool Success(const llvm::APSInt &SI, const Expr *E) { @@ -1343,7 +1401,7 @@ public: "Invalid evaluation result."); assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); - Result = APValue(SI); + Result = CCValue(SI); return true; } @@ -1352,7 +1410,7 @@ public: "Invalid evaluation result."); assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); - Result = APValue(APSInt(I)); + Result = CCValue(APSInt(I)); Result.getInt().setIsUnsigned( E->getType()->isUnsignedIntegerOrEnumerationType()); return true; @@ -1361,7 +1419,7 @@ public: bool Success(uint64_t Value, const Expr *E) { assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); - Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + Result = CCValue(Info.Ctx.MakeIntValue(Value, E->getType())); return true; } @@ -1380,7 +1438,7 @@ public: return false; } - bool Success(const APValue &V, const Expr *E) { + bool Success(const CCValue &V, const Expr *E) { return Success(V.getInt(), E); } bool Error(const Expr *E) { @@ -1472,13 +1530,14 @@ private: /// an integer rvalue to produce a pointer (represented as an lvalue) instead. /// Some simple arithmetic on such values is supported (they are treated much /// like char*). -static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { +static bool EvaluateIntegerOrLValue(const Expr* E, CCValue &Result, + EvalInfo &Info) { assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType()); return IntExprEvaluator(Info, Result).Visit(E); } static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { - APValue Val; + CCValue Val; if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) return false; Result = Val.getInt(); @@ -1890,33 +1949,32 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } // The LHS of a constant expr is always evaluated and needed. - APValue LHSVal; + CCValue LHSVal; if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info)) return false; // error in subexpression. if (!Visit(E->getRHS())) return false; - APValue &RHSVal = Result; + CCValue &RHSVal = Result; // Handle cases like (unsigned long)&a + 4. if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) { - CharUnits Offset = LHSVal.getLValueOffset(); CharUnits AdditionalOffset = CharUnits::fromQuantity( RHSVal.getInt().getZExtValue()); if (E->getOpcode() == BO_Add) - Offset += AdditionalOffset; + LHSVal.getLValueOffset() += AdditionalOffset; else - Offset -= AdditionalOffset; - Result = APValue(LHSVal.getLValueBase(), Offset); + LHSVal.getLValueOffset() -= AdditionalOffset; + Result = LHSVal; return true; } // Handle cases like 4 + (unsigned long)&a if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) { - CharUnits Offset = RHSVal.getLValueOffset(); - Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue()); - Result = APValue(RHSVal.getLValueBase(), Offset); + RHSVal.getLValueOffset() += CharUnits::fromQuantity( + LHSVal.getInt().getZExtValue()); + // Note that RHSVal is Result. return true; } @@ -2145,7 +2203,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return false; // Get the operand value. - APValue Val; + CCValue Val; if (!Evaluate(Val, Info, E->getSubExpr())) return false; @@ -2330,7 +2388,7 @@ public: FloatExprEvaluator(EvalInfo &info, APFloat &result) : ExprEvaluatorBaseTy(info), Result(result) {} - bool Success(const APValue &V, const Expr *e) { + bool Success(const CCValue &V, const Expr *e) { Result = V.getFloat(); return true; } @@ -2575,7 +2633,7 @@ public: ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result) : ExprEvaluatorBaseTy(info), Result(Result) {} - bool Success(const APValue &V, const Expr *e) { + bool Success(const CCValue &V, const Expr *e) { Result.setFrom(V); return true; } @@ -2915,7 +2973,7 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Top level Expr::EvaluateAsRValue method. //===----------------------------------------------------------------------===// -static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { +static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) { // In C, function designators are not lvalues, but we evaluate them as if they // are. if (E->isGLValue() || E->getType()->isFunctionType()) { @@ -2938,7 +2996,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { llvm::APFloat F(0.0); if (!EvaluateFloat(E, F, Info)) return false; - Result = APValue(F); + Result = CCValue(F); } else if (E->getType()->isAnyComplexType()) { ComplexValue C; if (!EvaluateComplex(E, C, Info)) @@ -2959,25 +3017,31 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); - if (!::Evaluate(Result.Val, Info, this)) + CCValue Value; + if (!::Evaluate(Value, Info, this)) return false; if (isGLValue()) { LValue LV; - LV.setFrom(Result.Val); - return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val); + LV.setFrom(Value); + if (!HandleLValueToRValueConversion(Info, getType(), LV, Value)) + return false; } - // FIXME: We don't allow expressions to fold to pointers to locals. Code which - // calls EvaluateAsRValue() isn't ready for that yet. - return !Result.Val.isLValue() || IsGlobalLValue(Result.Val.getLValueBase()); + // Check this core constant expression is a constant expression, and if so, + // slice it down to one. + if (!CheckConstantExpression(Value)) + return false; + Result.Val = Value; + return true; } bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const { EvalResult Scratch; return EvaluateAsRValue(Scratch, Ctx) && - HandleConversionToBool(Scratch.Val, Result); + HandleConversionToBool(CCValue(Scratch.Val, CCValue::NoCallIndex), + Result); } bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { @@ -2996,7 +3060,7 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { LValue LV; if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects && IsGlobalLValue(LV.Base)) { - LV.moveInto(Result.Val); + Result.Val = APValue(LV.Base, LV.Offset); return true; } return false; @@ -3007,8 +3071,10 @@ bool Expr::EvaluateAsAnyLValue(EvalResult &Result, EvalInfo Info(Ctx, Result); LValue LV; - if (EvaluateLValue(this, LV, Info)) { - LV.moveInto(Result.Val); + // Don't allow references to out-of-scope function parameters to escape. + if (EvaluateLValue(this, LV, Info) && + (!IsParamLValue(LV.Base) || LV.CallIndex == CCValue::NoCallIndex)) { + Result.Val = APValue(LV.Base, LV.Offset); return true; } return false; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 4ecc53c61b89d05ec46e7d74f0f447b809ca9e9d..b1ca20f4bcaeb94429572a77c75363eab96ae4a5 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 %s // FIXME: support const T& parameters here. //template constexpr T id(const T &t) { return t; } @@ -10,8 +10,8 @@ template constexpr T id(T t) { return t; } //template constexpr T max(const T &a, const T &b) { // return a < b ? b : a; //} -constexpr int min(int a, int b) { return a < b ? a : b; } -constexpr int max(int a, int b) { return a < b ? b : a; } +constexpr int min(const int &a, const int &b) { return a < b ? a : b; } +constexpr int max(const int &a, const int &b) { return a < b ? b : a; } struct MemberZero { constexpr int zero() { return 0; } @@ -91,3 +91,31 @@ namespace StaticMemberFunction { using check_static_call = int[s.f(19)]; using check_static_call = int[800]; } + +namespace ParameterScopes { + + const int k = 42; + constexpr const int &ObscureTheTruth(const int &a) { return a; } + constexpr const int &MaybeReturnJunk(bool b, const int a) { + return ObscureTheTruth(b ? a : k); + } + constexpr int n1 = MaybeReturnJunk(false, 0); // ok + constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}} + + constexpr int InternalReturnJunk(int n) { + // FIXME: We should reject this: it never produces a constant expression. + return MaybeReturnJunk(true, n); + } + constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} + + constexpr int LToR(int &n) { return n; } + constexpr int GrabCallersArgument(bool which, int a, int b) { + return LToR(which ? b : a); + } + constexpr int n4 = GrabCallersArgument(false, 1, 2); + constexpr int n5 = GrabCallersArgument(true, 4, 8); + // FIXME: this isn't an ICE yet. + using check_value = int[n4 + n5]; + using check_value = int[9]; + +}