[cfe-commits] r142844 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/ExprConstant.cpp test/SemaCXX/i-c-e-cxx.cpp
David Dean
david_dean at apple.com
Mon Oct 24 14:52:45 PDT 2011
My bots are hitting an assert after this change:
Assertion failed: (E->isRValue() && E->getType()->hasPointerRepresentation()), function EvaluatePointer, file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-gcc42-RA/llvm/tools/clang/lib/AST/ExprConstant.cpp, line 778.
0 clang 0x0000000101af0eb2 llvm::SmallVectorTemplateBase<llvm_regmatch_t, false>::grow(unsigned long) + 338
1 clang 0x0000000101af1e33 llvm::SmallVectorTemplateBase<llvm_regmatch_t, false>::grow(unsigned long) + 4307
2 libSystem.B.dylib 0x00007fff8573b67a _sigtramp + 26
3 libSystem.B.dylib 0x0000000000000004 _sigtramp + 2056014244
4 clang 0x0000000101af1332 llvm::SmallVectorTemplateBase<llvm_regmatch_t, false>::grow(unsigned long) + 1490
5 clang 0x0000000100bbd9a2 clang::Expr::Classification::getModifiable() const + 85250
6 clang 0x0000000100bbf4e3 clang::Expr::Classification::getModifiable() const + 92227
7 clang 0x0000000100baffea clang::Expr::Classification::getModifiable() const + 29514
8 clang 0x0000000100bbe6b4 clang::Expr::Classification::getModifiable() const + 88596
9 clang 0x0000000100bbcd2f clang::Expr::Classification::getModifiable() const + 82063
10 clang 0x0000000100bbd9e6 clang::Expr::Classification::getModifiable() const + 85318
11 clang 0x0000000100bbfe25 clang::Expr::Classification::getModifiable() const + 94597
12 clang 0x0000000100baca0d clang::Expr::Classification::getModifiable() const + 15725
13 clang 0x0000000100bb4121 clang::Expr::Classification::getModifiable() const + 46209
14 clang 0x0000000100bb5fc0 clang::Expr::Classification::getModifiable() const + 54048
15 clang 0x0000000100bb6415 clang::Expr::Classification::getModifiable() const + 55157
16 clang 0x00000001008dbf82 llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 87314
17 clang 0x00000001008d5b4d llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 61661
18 clang 0x00000001008d842c llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 72124
19 clang 0x00000001008d5e1f llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 62383
20 clang 0x00000001008d58ee llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 61054
21 clang 0x00000001008dc099 llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 87593
22 clang 0x00000001008dce30 llvm::DenseMap<clang::Stmt const*, clang::CFGBlock const*, llvm::DenseMapInfo<clang::Stmt const*>, llvm::DenseMapInfo<clang::CFGBlock const*> >::grow(unsigned int) + 91072
23 clang 0x00000001008c0be9 llvm::DenseMap<clang::ento::SymbolData const*, clang::ento::SymbolReaper::SymbolStatus, llvm::DenseMapInfo<clang::ento::SymbolData const*>, llvm::DenseMapInfo<clang::ento::SymbolReaper::SymbolStatus> >::grow(unsigned int) + 3033
24 clang 0x00000001003b0016 clang::Parser::ConsumeAnyToken() + 22310
25 clang 0x00000001003d86e8 clang::Expr** llvm::PointerUnion<clang::Expr*, clang::Expr**>::get<clang::Expr**>() const + 38152
26 clang 0x0000000100479e2d clang::CanQual<clang::ReferenceType>::CreateUnsafe(clang::QualType) + 127789
27 clang 0x0000000100732b4b llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 54219
28 clang 0x0000000100733657 llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 57047
29 clang 0x0000000100733105 llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 55685
30 clang 0x0000000100733657 llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 57047
31 clang 0x0000000100733105 llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 55685
32 clang 0x0000000100733657 llvm::cast_retty<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >::ret_type llvm::cast<clang::TemplateSpecializationType, clang::CanQual<clang::Type> >(clang::CanQual<clang::Type> const&) + 57047
33 clang 0x00000001003d890d clang::Expr** llvm::PointerUnion<clang::Expr*, clang::Expr**>::get<clang::Expr**>() const + 38701
34 clang 0x00000001003a8baf llvm::SmallVectorTemplateBase<clang::ParsedTemplateArgument, false>::grow(unsigned long) + 71839
35 clang 0x000000010032518b llvm::IRBuilder<true, llvm::ConstantFolder, llvm::IRBuilderDefaultInserter<true> >::CreateGEP(llvm::Value*, llvm::Value*, llvm::Twine const&) + 859
36 clang 0x00000001002ee24c llvm::ValueMapCallbackVH<llvm::Value const*, llvm::TrackingVH<llvm::Value>, llvm::ValueMapConfig<llvm::Value const*>, llvm::DenseMapInfo<llvm::TrackingVH<llvm::Value> > >::allUsesReplacedWith(llvm::Value*) + 4156
37 clang 0x0000000100030853 llvm::DenseMap<clang::IdentifierInfo const*, unsigned int, llvm::DenseMapInfo<clang::IdentifierInfo const*>, llvm::DenseMapInfo<unsigned int> >::grow(unsigned int) + 25475
38 clang 0x000000010000b645 llvm::raw_ostream::operator<<(char const*) + 1893
39 clang 0x0000000100002358
40 clang 0x000000010000a38e std::vector<std::string, std::allocator<std::string> >::operator=(std::vector<std::string, std::allocator<std::string> > const&) + 13774
41 clang 0x0000000100000c34
Stack dump:
0. Program arguments: /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/host-compiler/bin/clang -cc1 -triple x86_64-apple-macosx10.6.6 -emit-obj -disable-free -main-file-name CommandLine.cpp -pic-level 1 -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu core2 -target-linker-version 123.4 -coverage-file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support/Release+Asserts/CommandLine.o -resource-dir /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/host-compiler/bin/../lib/clang/3.1 -dependency-file /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support/Release+Asserts/CommandLine.d.tmp -MP -MT /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support/Release+Asserts/CommandLine.o -MT /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support/Release+Asserts/CommandLine.d -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/include -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/include -I /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/lib/Support -fmodule-cache-path /var/folders/K2/K2x7HyV8GZSimPbqHtjYKE+++TQ/-Tmp-/clang-module-cache -O3 -Woverloaded-virtual -Wcast-qual -Wall -W -Wno-unused-parameter -Wwrite-strings -fconst-strings -fdeprecated-macro -fdebug-compilation-dir /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support -ferror-limit 19 -fmessage-length 0 -stack-protector 1 -fblocks -fobjc-dispatch-method=mixed -fno-common -fdiagnostics-show-option -o /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/clang-build/lib/Support/Release+Asserts/CommandLine.o -x c++ /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/lib/Support/CommandLine.cpp
1. <eof> parser at end of file
2. /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/include/llvm/ADT/StringMap.h:295:18: instantiating function definition 'find'
3. /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/include/llvm/ADT/StringMap.h:417:12: instantiating function definition 'StringMapConstIterator'
4. /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin10-RA/llvm/include/llvm/ADT/StringMap.h:447:8: instantiating function definition 'AdvancePastEmptyBuckets'
clang: error: unable to execute command: Illegal instruction
clang: error: clang frontend command failed due to signal 2 (use -v to see invocation)
clang: note: diagnostic msg: Please submit a bug report to http://llvm.org/bugs/ and include command line arguments and all diagnostic information.
llvm[1]: Compiling CrashRecoveryContext.cpp for Release+Asserts build
On 24 Oct 2011, at 2:07 PM, Richard Smith wrote:
> Author: rsmith
> Date: Mon Oct 24 16:07:08 2011
> New Revision: 142844
>
> URL: http://llvm.org/viewvc/llvm-project?rev=142844&view=rev
> Log:
> Constant expression evaluation: evaluate lvalues as lvalues, and rvalues as
> rvalues, as C++11 constant evaluation semantics require. DeclRefs referring to
> references can now use the normal initialization-caching codepath, which
> incidentally fixes a crash in cyclic initialization of references.
>
> Modified:
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=142844&r1=142843&r2=142844&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Mon Oct 24 16:07:08 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=142844&r1=142843&r2=142844&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Oct 24 16:07:08 2011
> @@ -151,7 +151,7 @@
> 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 +183,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,
> @@ -278,10 +282,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());
> @@ -294,6 +299,52 @@
> return Quals.hasConst() && !Quals.hasVolatile();
> }
>
> +bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
> + const LValue &LValue, APValue &RValue) {
> + const Expr *Base = LValue.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 (!LValue.Offset.isZero())
> + return false;
> +
> + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
> + // In C++, const, non-volatile integers initialized with ICEs are ICEs.
> + // In C, they can also be folded, although they are not ICEs.
> + // In C++0x, constexpr variables are constant expressions too.
> + // We allow folding any const variable of literal type initialized with
> + // a constant expression.
> + const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
> + if (VD && IsConstNonVolatile(VD->getType()) && Type->isLiteralType()) {
> + APValue *V = EvaluateVarDeclInit(Info, VD);
> + if (V && !V->isUninit()) {
> + RValue = *V;
> + return true;
> + }
> + }
> + 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(RValue, Info, CLE->getInitializer());
> + }
> +
> + return false;
> +}
> +
> namespace {
> class HasSideEffect
> : public ConstStmtVisitor<HasSideEffect, bool> {
> @@ -454,7 +505,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 +513,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 +528,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 +547,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 +581,10 @@
>
> //===----------------------------------------------------------------------===//
> // 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).
> //===----------------------------------------------------------------------===//
> namespace {
> class LValueExprEvaluator
> @@ -542,13 +622,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,6 +637,11 @@
> };
> } // 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) {
> return LValueExprEvaluator(Info, Result).Visit(E);
> }
> @@ -570,22 +655,24 @@
> // 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!
> -
> - // Check for recursive initializers of references.
> - if (PrevDecl == VD)
> - return Error(E);
> - PrevDecl = VD;
> - if (const Expr *Init = VD->getAnyInitializer())
> - return Visit(Init);
> + APValue *V = EvaluateVarDeclInit(Info, VD);
> + if (V && !V->isUninit()) {
> + assert(V->isLValue() && "reference init not glvalue");
> + Result.Base = V->getLValueBase();
> + Result.Offset = V->getLValueOffset();
> + return true;
> + }
> }
> }
>
> - 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);
> }
>
> @@ -617,6 +704,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 +775,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 +831,6 @@
> default:
> break;
>
> - case CK_NoOp:
> case CK_BitCast:
> case CK_CPointerToObjCPointerCast:
> case CK_BlockPointerToObjCPointerCast:
> @@ -810,7 +900,7 @@
> return EvaluateLValue(SubExpr, Result, Info);
> }
>
> - return false;
> + return ExprEvaluatorBaseTy::VisitCastExpr(E);
> }
>
> bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
> @@ -852,7 +942,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 +953,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 +1015,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 +1102,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 +1189,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 +1244,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 +1286,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 +1488,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 +1501,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 +1670,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 +1733,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 +1745,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 +1915,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);
> }
> @@ -1918,7 +2000,7 @@
>
> case CK_LValueToRValue:
> case CK_NoOp:
> - return Visit(E->getSubExpr());
> + return ExprEvaluatorBaseTy::VisitCastExpr(E);
>
> case CK_MemberPointerToBoolean:
> case CK_PointerToBoolean:
> @@ -1927,7 +2009,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 +2132,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 +2221,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 +2310,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 +2378,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 +2451,7 @@
>
> case CK_LValueToRValue:
> case CK_NoOp:
> - return Visit(E->getSubExpr());
> + return ExprEvaluatorBaseTy::VisitCastExpr(E);
>
> case CK_Dependent:
> case CK_GetObjCProperty:
> @@ -2634,27 +2695,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;
> @@ -2670,25 +2732,43 @@
> /// 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);
> + } else if (Result.Val.isLValue()) {
> + // FIXME: We don't allow expressions to fold to references to locals. Code
> + // which calls Evaluate() isn't ready for that yet. For instance, we don't
> + // have any checking that the initializer of a pointer in C is an address
> + // constant.
> + if (!IsGlobalLValue(Result.Val.getLValueBase()))
> + return false;
> + }
> +
> + return true;
> }
>
> 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 {
> @@ -3184,11 +3264,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/SemaCXX/i-c-e-cxx.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp?rev=142844&r1=142843&r2=142844&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp (original)
> +++ cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp Mon Oct 24 16:07:08 2011
> @@ -66,3 +66,6 @@
> int arr[nonconst]; // expected-warning {{folded to constant array as an extension}}
> const int castfloat = static_cast<int>(1.0);
> int arr2[castfloat]; // ok
> +
> +extern const int &Recurse1;
> +const int &Recurse2 = Recurse1, &Recurse1 = Recurse2;
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
-David
More information about the cfe-commits
mailing list