Hi Chad, Thanks for the excellent testcase! Fixed in r143250.
On Fri, October 28, 2011 21:21, Chad Rosier wrote: > 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::AnalysisBasedW > arnings::Policy, clang::sema::FunctionScopeInfo*, clang::Decl const*, > clang::BlockExpr const*) + 2198 > 20 clang 0x0000000108b93c9f > clang::Sema::PopFunctionOrBlockScope(clang::sema::AnalysisBasedWarnings::Poli > cy 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::ParsingDec > lSpec&, clang::AccessSpecifier) + 858 26 clang 0x0000000108b75399 > clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, > clang::AccessSpecifier) + 393 > 27 clang 0x0000000108b7434f > clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRa > nge&, 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: > > > > 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-m >> ember.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-express >> ion-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
