Hi Richard, I'm seeing assertion failures on some of our testers, which bisected to this revision.
Assertion failed: (E->isRValue() && E->getType()->isRealFloatingType()), function EvaluateFloat, file /Users/mcrosier/llvm-clean/llvm/tools/clang/lib/AST/ExprConstant.cpp, line 2203. 0 clang 0x0000000109bb1c52 _ZL15PrintStackTracePv + 34 1 clang 0x0000000109bb2179 _ZL13SignalHandleri + 697 2 libsystem_c.dylib 0x00007fff8d815cfa _sigtramp + 26 3 libsystem_c.dylib 0x000000010a5ef278 _sigtramp + 18446603342611060120 4 clang 0x0000000109bb1ea6 abort + 22 5 clang 0x0000000109bb1e65 __assert_rtn + 53 6 clang 0x00000001090f7b6f (anonymous namespace)::FloatExprEvaluator::VisitBinaryOperator(clang::BinaryOperator const*) + 607 7 clang 0x00000001090f71e1 clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::FloatExprEvaluator, bool>::Visit(clang::Stmt const*) + 2865 8 clang 0x00000001090f71be clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::FloatExprEvaluator, bool>::Visit(clang::Stmt const*) + 2830 9 clang 0x00000001090f3841 (anonymous namespace)::IntExprEvaluator::VisitBinaryOperator(clang::BinaryOperator const*) + 2289 10 clang 0x00000001090f29e6 clang::StmtVisitorBase<clang::make_const_ptr, (anonymous namespace)::IntExprEvaluator, bool>::Visit(clang::Stmt const*) + 6262 11 clang 0x00000001090ec885 _ZL8EvaluateRN5clang7APValueERN12_GLOBAL__N_18EvalInfoEPKNS_4ExprE + 325 12 clang 0x00000001090ec645 clang::Expr::Evaluate(clang::Expr::EvalResult&, clang::ASTContext const&) const + 69 13 clang 0x00000001090ed192 clang::Expr::EvaluateAsBooleanCondition(bool&, clang::ASTContext const&) const + 50 14 clang 0x0000000108ee3fac (anonymous namespace)::CFGBuilder::Visit(clang::Stmt*, (anonymous namespace)::AddStmtChoice) + 10940 15 clang 0x0000000108ee5d57 (anonymous namespace)::CFGBuilder::VisitCompoundStmt(clang::CompoundStmt*) + 119 16 clang 0x0000000108ee4c68 (anonymous namespace)::CFGBuilder::Visit(clang::Stmt*, (anonymous namespace)::AddStmtChoice) + 14200 17 clang 0x0000000108edc4fb clang::CFG::buildCFG(clang::Decl const*, clang::Stmt*, clang::ASTContext*, clang::CFG::BuildOptions const&) + 1531 18 clang 0x0000000108ed90ed clang::AnalysisDeclContext::getCFG() + 77 19 clang 0x0000000108b7a966 clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::BlockExpr const*) + 2198 20 clang 0x0000000108b93c9f clang::Sema::PopFunctionOrBlockScope(clang::sema::AnalysisBasedWarnings::Policy const*, clang::Decl const*, clang::BlockExpr const*) + 95 21 clang 0x0000000108c243d6 clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool) + 1510 22 clang 0x0000000108b68634 clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) + 244 23 clang 0x0000000108b75fe1 clang::Parser::ParseFunctionDefinition(clang::Parser::ParsingDeclarator&, clang::Parser::ParsedTemplateInfo const&) + 2241 24 clang 0x0000000108b2813c clang::Parser::ParseDeclGroup(clang::Parser::ParsingDeclSpec&, unsigned int, bool, clang::SourceLocation*, clang::Parser::ForRangeInit*) + 1020 25 clang 0x0000000108b7519a clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsingDeclSpec&, clang::AccessSpecifier) + 858 26 clang 0x0000000108b75399 clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::AccessSpecifier) + 393 27 clang 0x0000000108b7434f clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, clang::Parser::ParsingDeclSpec*) + 3295 28 clang 0x0000000108b735f7 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&) + 247 29 clang 0x0000000108b1e0ed clang::ParseAST(clang::Sema&, bool) + 317 30 clang 0x0000000108aec920 clang::CodeGenAction::ExecuteAction() + 1040 31 clang 0x00000001088fe48b clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 955 32 clang 0x00000001088e8318 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) + 2792 33 clang 0x00000001088e0aa3 cc1_main(char const**, char const**, char const*, void*) + 5219 34 clang 0x00000001088e475f main + 687 35 clang 0x00000001088df634 start + 52 Here's a delta reduced test case:
foo.i
Description: Binary data
Reproduce with: clang -Os -arch i386 -c foo.i -o /dev/null Please take a moment to investigate. Regards, Chad On Oct 28, 2011, at 10:51 AM, Richard Smith wrote: > Author: rsmith > Date: Fri Oct 28 12:51:58 2011 > New Revision: 143204 > > URL: http://llvm.org/viewvc/llvm-project?rev=143204&view=rev > Log: > Reinstate r142844 (reverted in r142872) now that lvalue-to-rvalue conversions > are present in all the necessary places: > > In constant expression evaluation, evaluate lvalues as lvalues and rvalues as > rvalues. Remove special case for caching reference initialization and fix a > cyclic initialization crash in the process. > > Modified: > cfe/trunk/include/clang/AST/ASTContext.h > cfe/trunk/include/clang/AST/Expr.h > cfe/trunk/lib/AST/ExprConstant.cpp > cfe/trunk/test/CodeGenCXX/static-data-member.cpp > cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp > > Modified: cfe/trunk/include/clang/AST/ASTContext.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=143204&r1=143203&r2=143204&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/ASTContext.h (original) > +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Oct 28 12:51:58 2011 > @@ -1274,7 +1274,7 @@ > CanQualType getCanonicalParamType(QualType T) const; > > /// \brief Determine whether the given types are equivalent. > - bool hasSameType(QualType T1, QualType T2) { > + bool hasSameType(QualType T1, QualType T2) const { > return getCanonicalType(T1) == getCanonicalType(T2); > } > > @@ -1294,7 +1294,7 @@ > > /// \brief Determine whether the given types are equivalent after > /// cvr-qualifiers have been removed. > - bool hasSameUnqualifiedType(QualType T1, QualType T2) { > + bool hasSameUnqualifiedType(QualType T1, QualType T2) const { > return getCanonicalType(T1).getTypePtr() == > getCanonicalType(T2).getTypePtr(); > } > > Modified: cfe/trunk/include/clang/AST/Expr.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143204&r1=143203&r2=143204&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/Expr.h (original) > +++ cfe/trunk/include/clang/AST/Expr.h Fri Oct 28 12:51:58 2011 > @@ -465,7 +465,8 @@ > /// Evaluate - Return true if this is a constant which we can fold using > /// any crazy technique (that has nothing to do with language standards) > that > /// we want to. If this function returns true, it returns the folded > constant > - /// in Result. > + /// in Result. If this expression is a glvalue, an lvalue-to-rvalue > conversion > + /// will be applied. > bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const; > > /// EvaluateAsBooleanCondition - Return true if this is a constant > > Modified: cfe/trunk/lib/AST/ExprConstant.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143204&r1=143203&r2=143204&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ExprConstant.cpp (original) > +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Oct 28 12:51:58 2011 > @@ -148,10 +148,13 @@ > if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E)) > return CLE->isFileScope(); > > + if (isa<MemberExpr>(E)) > + return false; > + > return true; > } > > -static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { > +static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { > const Expr* Base = Value.Base; > > // A null base expression indicates a null pointer. These are always > @@ -183,40 +186,44 @@ > return true; > } > > -static bool HandleConversionToBool(const Expr* E, bool& Result, > - EvalInfo &Info) { > - if (E->getType()->isIntegralOrEnumerationType()) { > - APSInt IntResult; > - if (!EvaluateInteger(E, IntResult, Info)) > - return false; > - Result = IntResult != 0; > +static bool HandleConversionToBool(const APValue &Val, bool &Result) { > + switch (Val.getKind()) { > + case APValue::Uninitialized: > + return false; > + case APValue::Int: > + Result = Val.getInt().getBoolValue(); > return true; > - } else if (E->getType()->isRealFloatingType()) { > - APFloat FloatResult(0.0); > - if (!EvaluateFloat(E, FloatResult, Info)) > - return false; > - Result = !FloatResult.isZero(); > + case APValue::Float: > + Result = !Val.getFloat().isZero(); > return true; > - } else if (E->getType()->hasPointerRepresentation()) { > - LValue PointerResult; > - if (!EvaluatePointer(E, PointerResult, Info)) > - return false; > - return EvalPointerValueAsBool(PointerResult, Result); > - } else if (E->getType()->isAnyComplexType()) { > - ComplexValue ComplexResult; > - if (!EvaluateComplex(E, ComplexResult, Info)) > - return false; > - if (ComplexResult.isComplexFloat()) { > - Result = !ComplexResult.getComplexFloatReal().isZero() || > - !ComplexResult.getComplexFloatImag().isZero(); > - } else { > - Result = ComplexResult.getComplexIntReal().getBoolValue() || > - ComplexResult.getComplexIntImag().getBoolValue(); > - } > + case APValue::ComplexInt: > + Result = Val.getComplexIntReal().getBoolValue() || > + Val.getComplexIntImag().getBoolValue(); > + return true; > + case APValue::ComplexFloat: > + Result = !Val.getComplexFloatReal().isZero() || > + !Val.getComplexFloatImag().isZero(); > return true; > + case APValue::LValue: > + { > + LValue PointerResult; > + PointerResult.setFrom(Val); > + return EvalPointerValueAsBool(PointerResult, Result); > + } > + case APValue::Vector: > + return false; > } > > - return false; > + llvm_unreachable("unknown APValue kind"); > +} > + > +static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, > + EvalInfo &Info) { > + assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition"); > + APValue Val; > + if (!Evaluate(Val, Info, E)) > + return false; > + return HandleConversionToBool(Val, Result); > } > > static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, > @@ -263,6 +270,8 @@ > > /// Try to evaluate the initializer for a variable declaration. > static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) { > + // FIXME: If this is a parameter to an active constexpr function call, > perform > + // substitution now. > if (isa<ParmVarDecl>(VD)) > return 0; > > @@ -278,10 +287,11 @@ > > VD->setEvaluatingValue(); > > - // FIXME: If the initializer isn't a constant expression, propagate up any > - // diagnostic explaining why not. > Expr::EvalResult EResult; > - if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects) > + EvalInfo InitInfo(Info.Ctx, EResult); > + // 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 > VD->setEvaluatedValue(APValue()); > @@ -289,11 +299,92 @@ > return VD->getEvaluatedValue(); > } > > -bool IsConstNonVolatile(QualType T) { > +static bool IsConstNonVolatile(QualType T) { > Qualifiers Quals = T.getQualifiers(); > return Quals.hasConst() && !Quals.hasVolatile(); > } > > +bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, > + const LValue &LVal, APValue &RVal) { > + const Expr *Base = LVal.Base; > + > + // FIXME: Indirection through a null pointer deserves a diagnostic. > + if (!Base) > + return false; > + > + // FIXME: Support accessing subobjects of objects of literal types. A > simple > + // byte offset is insufficient for C++11 semantics: we need to know how the > + // reference was formed (which union member was named, for instance). > + // FIXME: Support subobjects of StringLiteral and PredefinedExpr. > + if (!LVal.Offset.isZero()) > + return false; > + > + const Decl *D = 0; > + > + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { > + // If the lvalue has been cast to some other type, don't try to read it. > + // FIXME: Could simulate a bitcast here. > + if (!Info.Ctx.hasSameUnqualifiedType(Type, DRE->getType())) > + return false; > + D = DRE->getDecl(); > + } > + > + // FIXME: Static data members accessed via a MemberExpr are represented as > + // that MemberExpr. We should use the Decl directly instead. > + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { > + if (!Info.Ctx.hasSameUnqualifiedType(Type, ME->getType())) > + return false; > + D = ME->getMemberDecl(); > + assert(!isa<FieldDecl>(D) && "shouldn't see fields here"); > + } > + > + if (D) { > + // In C++98, const, non-volatile integers initialized with ICEs are ICEs. > + // In C++11, constexpr, non-volatile variables initialized with constant > + // expressions are constant expressions too. > + // In C, such things can also be folded, although they are not ICEs. > + // > + // FIXME: Allow folding any const variable of literal type initialized > with > + // a constant expression. For now, we only allow variables with integral > and > + // floating types to be folded. > + const VarDecl *VD = dyn_cast<VarDecl>(D); > + if (!VD || !IsConstNonVolatile(VD->getType()) || > + (!Type->isIntegralOrEnumerationType() && > !Type->isRealFloatingType())) > + return false; > + > + APValue *V = EvaluateVarDeclInit(Info, VD); > + if (!V || V->isUninit()) > + return false; > + > + if (!VD->getAnyInitializer()->isLValue()) { > + RVal = *V; > + 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()) > + return false; > + } > + > + // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator > and > + // here. > + > + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the > + // initializer until now for such expressions. Such an expression can't be > + // an ICE in C, so this only matters for fold. > + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { > + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in > c++?"); > + return Evaluate(RVal, Info, CLE->getInitializer()); > + } > + > + return false; > +} > + > namespace { > class HasSideEffect > : public ConstStmtVisitor<HasSideEffect, bool> { > @@ -454,7 +545,7 @@ > return DerivedError(E); > > bool cond; > - if (!HandleConversionToBool(E->getCond(), cond, Info)) > + if (!EvaluateAsBooleanCondition(E->getCond(), cond, Info)) > return DerivedError(E); > > return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr()); > @@ -462,10 +553,10 @@ > > RetTy VisitConditionalOperator(const ConditionalOperator *E) { > bool BoolResult; > - if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) > + if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) > return DerivedError(E); > > - Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); > + Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); > return StmtVisitorTy::Visit(EvalExpr); > } > > @@ -477,6 +568,9 @@ > return DerivedSuccess(*value, E); > } > > + RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { > + return StmtVisitorTy::Visit(E->getInitializer()); > + } > RetTy VisitInitListExpr(const InitListExpr *E) { > if (Info.getLangOpts().CPlusPlus0x) { > if (E->getNumInits() == 0) > @@ -493,6 +587,28 @@ > return DerivedValueInitialization(E); > } > > + RetTy VisitCastExpr(const CastExpr *E) { > + switch (E->getCastKind()) { > + default: > + break; > + > + case CK_NoOp: > + return StmtVisitorTy::Visit(E->getSubExpr()); > + > + case CK_LValueToRValue: { > + LValue LVal; > + if (EvaluateLValue(E->getSubExpr(), LVal, Info)) { > + APValue RVal; > + if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal)) > + return DerivedSuccess(RVal, E); > + } > + break; > + } > + } > + > + return DerivedError(E); > + } > + > /// Visit a value which is evaluated, but whose value is ignored. > void VisitIgnoredValue(const Expr *E) { > APValue Scratch; > @@ -505,6 +621,23 @@ > > //===----------------------------------------------------------------------===// > // LValue Evaluation > +// > +// This is used for evaluating lvalues (in C and C++), xvalues (in C++11), > +// function designators (in C), decl references to void objects (in C), and > +// temporaries (if building with -Wno-address-of-temporary). > +// > +// LValue evaluation produces values comprising a base expression of one of > the > +// following types: > +// * DeclRefExpr > +// * MemberExpr for a static member > +// * CompoundLiteralExpr in C > +// * StringLiteral > +// * PredefinedExpr > +// * ObjCEncodeExpr > +// * AddrLabelExpr > +// * BlockExpr > +// * CallExpr for a MakeStringConstant builtin > +// plus an offset in bytes. > //===----------------------------------------------------------------------===// > namespace { > class LValueExprEvaluator > @@ -530,6 +663,8 @@ > return false; > } > > + bool VisitVarDecl(const Expr *E, const VarDecl *VD); > + > bool VisitDeclRefExpr(const DeclRefExpr *E); > bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } > bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); > @@ -542,13 +677,13 @@ > bool VisitCastExpr(const CastExpr *E) { > switch (E->getCastKind()) { > default: > - return false; > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > > - case CK_NoOp: > case CK_LValueBitCast: > return Visit(E->getSubExpr()); > > - // FIXME: Support CK_DerivedToBase and friends. > + // FIXME: Support CK_DerivedToBase and CK_UncheckedDerivedToBase. > + // Reuse PointerExprEvaluator::VisitCastExpr for these. > } > } > > @@ -557,39 +692,52 @@ > }; > } // end anonymous namespace > > +/// Evaluate an expression as an lvalue. This can be legitimately called on > +/// expressions which are not glvalues, in a few cases: > +/// * function designators in C, > +/// * "extern void" objects, > +/// * temporaries, if building with -Wno-address-of-temporary. > static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { > + assert((E->isGLValue() || E->getType()->isFunctionType() || > + E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) && > + "can't evaluate expression as an lvalue"); > return LValueExprEvaluator(Info, Result).Visit(E); > } > > bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { > - if (isa<FunctionDecl>(E->getDecl())) { > + if (isa<FunctionDecl>(E->getDecl())) > return Success(E); > - } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { > - if (!VD->getType()->isReferenceType()) > - return Success(E); > - // Reference parameters can refer to anything even if they have an > - // "initializer" in the form of a default argument. > - if (!isa<ParmVarDecl>(VD)) { > - // FIXME: Check whether VD might be overridden! > + if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) > + return VisitVarDecl(E, VD); > + return Error(E); > +} > > - // Check for recursive initializers of references. > - if (PrevDecl == VD) > - return Error(E); > - PrevDecl = VD; > - if (const Expr *Init = VD->getAnyInitializer()) > - return Visit(Init); > - } > - } > +bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { > + if (!VD->getType()->isReferenceType()) > + return Success(E); > + > + APValue *V = EvaluateVarDeclInit(Info, VD); > + if (V && !V->isUninit()) > + return Success(*V, E); > > - return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); > + return Error(E); > } > > bool > LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { > + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); > + // Defer visiting the literal until the lvalue-to-rvalue conversion. We can > + // only see this when folding in C, so there's no standard to follow here. > return Success(E); > } > > bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { > + // Handle static data members. > + if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) { > + VisitIgnoredValue(E->getBase()); > + return VisitVarDecl(E, VD); > + } > + > QualType Ty; > if (E->isArrow()) { > if (!EvaluatePointer(E->getBase(), Result, Info)) > @@ -617,6 +765,10 @@ > } > > bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr > *E) { > + // FIXME: Deal with vectors as array subscript bases. > + if (E->getBase()->getType()->isVectorType()) > + return false; > + > if (!EvaluatePointer(E->getBase(), Result, Info)) > return false; > > @@ -684,7 +836,7 @@ > } // end anonymous namespace > > static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { > - assert(E->getType()->hasPointerRepresentation()); > + assert(E->isRValue() && E->getType()->hasPointerRepresentation()); > return PointerExprEvaluator(Info, Result).Visit(E); > } > > @@ -740,7 +892,6 @@ > default: > break; > > - case CK_NoOp: > case CK_BitCast: > case CK_CPointerToObjCPointerCast: > case CK_BlockPointerToObjCPointerCast: > @@ -810,7 +961,7 @@ > return EvaluateLValue(SubExpr, Result, Info); > } > > - return false; > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > } > > bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { > @@ -852,7 +1003,6 @@ > bool VisitUnaryReal(const UnaryOperator *E) > { return Visit(E->getSubExpr()); } > bool VisitCastExpr(const CastExpr* E); > - bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); > bool VisitInitListExpr(const InitListExpr *E); > bool VisitUnaryImag(const UnaryOperator *E); > // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div, > @@ -864,8 +1014,7 @@ > } // end anonymous namespace > > static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { > - if (!E->getType()->isVectorType()) > - return false; > + assert(E->isRValue() && E->getType()->isVectorType() &&"not a vector > rvalue"); > return VectorExprEvaluator(Info, Result).Visit(E); > } > > @@ -927,20 +1076,12 @@ > } > return Success(Elts, E); > } > - case CK_LValueToRValue: > - case CK_NoOp: > - return Visit(SE); > default: > - return Error(E); > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > } > } > > bool > -VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { > - return Visit(E->getInitializer()); > -} > - > -bool > VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { > const VectorType *VT = E->getType()->castAs<VectorType>(); > unsigned NumInits = E->getNumInits(); > @@ -1022,6 +1163,10 @@ > > //===----------------------------------------------------------------------===// > // Integer Evaluation > +// > +// As a GNU extension, we support casting pointers to sufficiently-wide > integer > +// types and back in constant folding. Integer values are thus represented > +// either as an integer-valued APValue, or as an lvalue-valued APValue. > //===----------------------------------------------------------------------===// > > namespace { > @@ -1105,8 +1250,7 @@ > } > bool VisitMemberExpr(const MemberExpr *E) { > if (CheckReferencedDecl(E, E->getMemberDecl())) { > - // Conservatively assume a MemberExpr will have side-effects > - Info.EvalStatus.HasSideEffects = true; > + VisitIgnoredValue(E->getBase()); > return true; > } > > @@ -1161,14 +1305,20 @@ > }; > } // end anonymous namespace > > +/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, > and > +/// produce either the integer value or a pointer. > +/// > +/// GCC has a heinous extension which folds casts between pointer types and > +/// pointer-sized integral types. We support this by allowing the evaluation > of > +/// 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) { > - assert(E->getType()->isIntegralOrEnumerationType()); > + assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType()); > return IntExprEvaluator(Info, Result).Visit(E); > } > > static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { > - assert(E->getType()->isIntegralOrEnumerationType()); > - > APValue Val; > if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) > return false; > @@ -1197,18 +1347,6 @@ > return Success(Val, E); > } > } > - > - // In C++, const, non-volatile integers initialized with ICEs are ICEs. > - // In C, they can also be folded, although they are not ICEs. > - if (IsConstNonVolatile(E->getType())) { > - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { > - APValue *V = EvaluateVarDeclInit(Info, VD); > - if (V && V->isInt()) > - return Success(V->getInt(), E); > - } > - } > - > - // Otherwise, random variable references are not constants. > return false; > } > > @@ -1411,6 +1549,9 @@ > } > > bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { > + if (E->isAssignmentOp()) > + return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); > + > if (E->getOpcode() == BO_Comma) { > VisitIgnoredValue(E->getLHS()); > return Visit(E->getRHS()); > @@ -1421,20 +1562,20 @@ > // necessarily integral > bool lhsResult, rhsResult; > > - if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { > + if (EvaluateAsBooleanCondition(E->getLHS(), lhsResult, Info)) { > // We were able to evaluate the LHS, see if we can get away with not > // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 > if (lhsResult == (E->getOpcode() == BO_LOr)) > return Success(lhsResult, E); > > - if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { > + if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) { > if (E->getOpcode() == BO_LOr) > return Success(lhsResult || rhsResult, E); > else > return Success(lhsResult && rhsResult, E); > } > } else { > - if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { > + if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) { > // We can't evaluate the LHS; however, sometimes the result > // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. > if (rhsResult == (E->getOpcode() == BO_LOr) || > @@ -1590,58 +1731,60 @@ > } > > // The LHS of a constant expr is always evaluated and needed. > - if (!Visit(E->getLHS())) > + APValue LHSVal; > + if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info)) > return false; // error in subexpression. > > - APValue RHSVal; > - if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info)) > + if (!Visit(E->getRHS())) > return false; > + APValue &RHSVal = Result; > > // Handle cases like (unsigned long)&a + 4. > - if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) { > - CharUnits Offset = Result.getLValueOffset(); > + 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; > else > Offset -= AdditionalOffset; > - Result = APValue(Result.getLValueBase(), Offset); > + Result = APValue(LHSVal.getLValueBase(), Offset); > return true; > } > > // Handle cases like 4 + (unsigned long)&a > if (E->getOpcode() == BO_Add && > - RHSVal.isLValue() && Result.isInt()) { > + RHSVal.isLValue() && LHSVal.isInt()) { > CharUnits Offset = RHSVal.getLValueOffset(); > - Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue()); > + Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue()); > Result = APValue(RHSVal.getLValueBase(), Offset); > return true; > } > > // All the following cases expect both operands to be an integer > - if (!Result.isInt() || !RHSVal.isInt()) > + if (!LHSVal.isInt() || !RHSVal.isInt()) > return false; > > - APSInt& RHS = RHSVal.getInt(); > + APSInt &LHS = LHSVal.getInt(); > + APSInt &RHS = RHSVal.getInt(); > > switch (E->getOpcode()) { > default: > return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); > - case BO_Mul: return Success(Result.getInt() * RHS, E); > - case BO_Add: return Success(Result.getInt() + RHS, E); > - case BO_Sub: return Success(Result.getInt() - RHS, E); > - case BO_And: return Success(Result.getInt() & RHS, E); > - case BO_Xor: return Success(Result.getInt() ^ RHS, E); > - case BO_Or: return Success(Result.getInt() | RHS, E); > + case BO_Mul: return Success(LHS * RHS, E); > + case BO_Add: return Success(LHS + RHS, E); > + case BO_Sub: return Success(LHS - RHS, E); > + case BO_And: return Success(LHS & RHS, E); > + case BO_Xor: return Success(LHS ^ RHS, E); > + case BO_Or: return Success(LHS | RHS, E); > case BO_Div: > if (RHS == 0) > return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); > - return Success(Result.getInt() / RHS, E); > + return Success(LHS / RHS, E); > case BO_Rem: > if (RHS == 0) > return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); > - return Success(Result.getInt() % RHS, E); > + return Success(LHS % RHS, E); > case BO_Shl: { > // During constant-folding, a negative shift is an opposite shift. > if (RHS.isSigned() && RHS.isNegative()) { > @@ -1651,8 +1794,8 @@ > > shift_left: > unsigned SA > - = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); > - return Success(Result.getInt() << SA, E); > + = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); > + return Success(LHS << SA, E); > } > case BO_Shr: { > // During constant-folding, a negative shift is an opposite shift. > @@ -1663,16 +1806,16 @@ > > shift_right: > unsigned SA = > - (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); > - return Success(Result.getInt() >> SA, E); > + (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); > + return Success(LHS >> SA, E); > } > > - case BO_LT: return Success(Result.getInt() < RHS, E); > - case BO_GT: return Success(Result.getInt() > RHS, E); > - case BO_LE: return Success(Result.getInt() <= RHS, E); > - case BO_GE: return Success(Result.getInt() >= RHS, E); > - case BO_EQ: return Success(Result.getInt() == RHS, E); > - case BO_NE: return Success(Result.getInt() != RHS, E); > + case BO_LT: return Success(LHS < RHS, E); > + case BO_GT: return Success(LHS > RHS, E); > + case BO_LE: return Success(LHS <= RHS, E); > + case BO_GE: return Success(LHS >= RHS, E); > + case BO_EQ: return Success(LHS == RHS, E); > + case BO_NE: return Success(LHS != RHS, E); > } > } > > @@ -1833,7 +1976,7 @@ > if (E->getOpcode() == UO_LNot) { > // LNot's operand isn't necessarily an integer, so we handle it specially. > bool bres; > - if (!HandleConversionToBool(E->getSubExpr(), bres, Info)) > + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) > return false; > return Success(!bres, E); > } > @@ -1842,8 +1985,9 @@ > if (!E->getSubExpr()->getType()->isIntegralOrEnumerationType()) > return false; > > - // Get the operand value into 'Result'. > - if (!Visit(E->getSubExpr())) > + // Get the operand value. > + APValue Val; > + if (!Evaluate(Val, Info, E->getSubExpr())) > return false; > > switch (E->getOpcode()) { > @@ -1854,16 +1998,16 @@ > case UO_Extension: > // FIXME: Should extension allow i-c-e extension expressions in its scope? > // If so, we could clear the diagnostic ID. > - return true; > + return Success(Val, E); > case UO_Plus: > - // The result is always just the subexpr. > - return true; > + // The result is just the value. > + return Success(Val, E); > case UO_Minus: > - if (!Result.isInt()) return false; > - return Success(-Result.getInt(), E); > + if (!Val.isInt()) return false; > + return Success(-Val.getInt(), E); > case UO_Not: > - if (!Result.isInt()) return false; > - return Success(~Result.getInt(), E); > + if (!Val.isInt()) return false; > + return Success(~Val.getInt(), E); > } > } > > @@ -1918,7 +2062,7 @@ > > case CK_LValueToRValue: > case CK_NoOp: > - return Visit(E->getSubExpr()); > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > > case CK_MemberPointerToBoolean: > case CK_PointerToBoolean: > @@ -1927,7 +2071,7 @@ > case CK_FloatingComplexToBoolean: > case CK_IntegralComplexToBoolean: { > bool BoolResult; > - if (!HandleConversionToBool(SubExpr, BoolResult, Info)) > + if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info)) > return false; > return Success(BoolResult, E); > } > @@ -2050,15 +2194,13 @@ > bool VisitUnaryReal(const UnaryOperator *E); > bool VisitUnaryImag(const UnaryOperator *E); > > - bool VisitDeclRefExpr(const DeclRefExpr *E); > - > // FIXME: Missing: array subscript of vector, member of vector, > // ImplicitValueInitExpr > }; > } // end anonymous namespace > > static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { > - assert(E->getType()->isRealFloatingType()); > + assert(E->isRValue() && E->getType()->isRealFloatingType()); > return FloatExprEvaluator(Info, Result).Visit(E); > } > > @@ -2141,21 +2283,6 @@ > } > } > > -bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { > - if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E)) > - return true; > - > - const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()); > - if (VD && IsConstNonVolatile(VD->getType())) { > - APValue *V = EvaluateVarDeclInit(Info, VD); > - if (V && V->isFloat()) { > - Result = V->getFloat(); > - return true; > - } > - } > - return false; > -} > - > bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { > if (E->getSubExpr()->getType()->isAnyComplexType()) { > ComplexValue CV; > @@ -2245,11 +2372,7 @@ > > switch (E->getCastKind()) { > default: > - return false; > - > - case CK_LValueToRValue: > - case CK_NoOp: > - return Visit(SubExpr); > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > > case CK_IntegralToFloating: { > APSInt IntResult; > @@ -2317,7 +2440,7 @@ > > static bool EvaluateComplex(const Expr *E, ComplexValue &Result, > EvalInfo &Info) { > - assert(E->getType()->isAnyComplexType()); > + assert(E->isRValue() && E->getType()->isAnyComplexType()); > return ComplexExprEvaluator(Info, Result).Visit(E); > } > > @@ -2390,7 +2513,7 @@ > > case CK_LValueToRValue: > case CK_NoOp: > - return Visit(E->getSubExpr()); > + return ExprEvaluatorBaseTy::VisitCastExpr(E); > > case CK_Dependent: > case CK_GetObjCProperty: > @@ -2634,27 +2757,28 @@ > //===----------------------------------------------------------------------===// > > static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { > - if (E->getType()->isVectorType()) { > + // In C, function designators are not lvalues, but we evaluate them as if > they > + // are. > + if (E->isGLValue() || E->getType()->isFunctionType()) { > + LValue LV; > + if (!EvaluateLValue(E, LV, Info)) > + return false; > + LV.moveInto(Result); > + } else if (E->getType()->isVectorType()) { > if (!EvaluateVector(E, Result, Info)) > return false; > } else if (E->getType()->isIntegralOrEnumerationType()) { > if (!IntExprEvaluator(Info, Result).Visit(E)) > return false; > - if (Result.isLValue() && > - !IsGlobalLValue(Result.getLValueBase())) > - return false; > } else if (E->getType()->hasPointerRepresentation()) { > LValue LV; > if (!EvaluatePointer(E, LV, Info)) > return false; > - if (!IsGlobalLValue(LV.Base)) > - return false; > LV.moveInto(Result); > } else if (E->getType()->isRealFloatingType()) { > llvm::APFloat F(0.0); > if (!EvaluateFloat(E, F, Info)) > return false; > - > Result = APValue(F); > } else if (E->getType()->isAnyComplexType()) { > ComplexValue C; > @@ -2667,36 +2791,50 @@ > return true; > } > > + > /// Evaluate - Return true if this is a constant which we can fold using > /// any crazy technique (that has nothing to do with language standards) that > /// we want to. If this function returns true, it returns the folded constant > -/// in Result. > +/// in Result. If this expression is a glvalue, an lvalue-to-rvalue > conversion > +/// will be applied to the result. > bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { > EvalInfo Info(Ctx, Result); > - return ::Evaluate(Result.Val, Info, this); > + > + if (!::Evaluate(Result.Val, Info, this)) > + return false; > + > + if (isGLValue()) { > + LValue LV; > + LV.setFrom(Result.Val); > + return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val); > + } > + > + // FIXME: We don't allow expressions to fold to pointers or references to > + // locals. Code which calls Evaluate() isn't ready for that yet. > + return !Result.Val.isLValue() || > IsGlobalLValue(Result.Val.getLValueBase()); > } > > bool Expr::EvaluateAsBooleanCondition(bool &Result, > const ASTContext &Ctx) const { > - EvalStatus Scratch; > - EvalInfo Info(Ctx, Scratch); > - > - return HandleConversionToBool(this, Result, Info); > + EvalResult Scratch; > + return Evaluate(Scratch, Ctx) && HandleConversionToBool(Scratch.Val, > Result); > } > > bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { > - EvalStatus Scratch; > - EvalInfo Info(Ctx, Scratch); > - > - return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects; > + EvalResult ExprResult; > + if (!Evaluate(ExprResult, Ctx) || ExprResult.HasSideEffects || > + !ExprResult.Val.isInt()) { > + return false; > + } > + Result = ExprResult.Val.getInt(); > + return true; > } > > bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { > EvalInfo Info(Ctx, Result); > > LValue LV; > - if (EvaluateLValue(this, LV, Info) && > - !Result.HasSideEffects && > + if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects && > IsGlobalLValue(LV.Base)) { > LV.moveInto(Result.Val); > return true; > @@ -3193,11 +3331,7 @@ > if (Loc) *Loc = d.Loc; > return false; > } > - EvalResult EvalResult; > - if (!Evaluate(EvalResult, Ctx)) > + if (!EvaluateAsInt(Result, Ctx)) > llvm_unreachable("ICE cannot be evaluated!"); > - assert(!EvalResult.HasSideEffects && "ICE with side effects!"); > - assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); > - Result = EvalResult.Val.getInt(); > return true; > } > > Modified: cfe/trunk/test/CodeGenCXX/static-data-member.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/static-data-member.cpp?rev=143204&r1=143203&r2=143204&view=diff > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/static-data-member.cpp (original) > +++ cfe/trunk/test/CodeGenCXX/static-data-member.cpp Fri Oct 28 12:51:58 2011 > @@ -64,3 +64,17 @@ > // CHECK-NEXT: br label > // CHECK: ret void > } > + > +// Test that we can fold member lookup expressions which resolve to static > data > +// members. > +namespace test4 { > + struct A { > + static const int n = 76; > + }; > + > + int f(A *a) { > + // CHECK: define i32 @_ZN5test41fEPNS_1AE > + // CHECK: ret i32 76 > + return a->n; > + } > +} > > 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=143204&r1=143203&r2=143204&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) > +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Oct 28 12:51:58 > 2011 > @@ -26,3 +26,17 @@ > } > } > } > + > +extern int &Recurse1; > +int &Recurse2 = Recurse1, &Recurse1 = Recurse2; > +constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized > by a constant expression}} > + > +namespace MemberEnum { > + struct WithMemberEnum { > + enum E { A = 42 }; > + } wme; > + // FIXME: b's initializer is not treated as a constant expression yet, but > we > + // can at least fold it. > + constexpr bool b = wme.A == 42; > + int n[b]; > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
