From: Eli Friedman Date: Sun, 14 Jun 2009 02:17:33 +0000 (+0000) Subject: PR4351: Add constant evaluation for constructs like "foo == NULL", where X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5bc86103767c2abcbfdd6518e0ccbbbb6aa59e0f;p=clang PR4351: Add constant evaluation for constructs like "foo == NULL", where foo has a constant address. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73321 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ff00bc24b3..4815ae5c3b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -62,6 +62,13 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); // Misc utilities //===----------------------------------------------------------------------===// +static bool EvalPointerValueAsBool(APValue& Value, bool& Result) { + // FIXME: Is this accurate for all kinds of bases? If not, what would + // the check look like? + Result = Value.getLValueBase() || Value.getLValueOffset(); + return true; +} + static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { if (E->getType()->isIntegralType()) { APSInt IntResult; @@ -79,10 +86,7 @@ static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { APValue PointerResult; if (!EvaluatePointer(E, PointerResult, Info)) return false; - // FIXME: Is this accurate for all kinds of bases? If not, what would - // the check look like? - Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset(); - return true; + return EvalPointerValueAsBool(PointerResult, Result); } else if (E->getType()->isAnyComplexType()) { APValue ComplexResult; if (!EvaluateComplex(E, ComplexResult, Info)) @@ -937,10 +941,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) return false; - // Reject any bases; this is conservative, but good enough for - // common uses - if (LHSValue.getLValueBase() || RHSValue.getLValueBase()) - return false; + // Reject any bases from the normal codepath; we special-case comparisons + // to null. + if (LHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (RHSValue.getLValueBase() || RHSValue.getLValueOffset()) + return false; + bool bres; + if (!EvalPointerValueAsBool(LHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + } else if (RHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (LHSValue.getLValueBase() || LHSValue.getLValueOffset()) + return false; + bool bres; + if (!EvalPointerValueAsBool(RHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + } if (E->getOpcode() == BinaryOperator::Sub) { const QualType Type = E->getLHS()->getType(); diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c index 971986b2d3..72db14c820 100644 --- a/test/Sema/const-eval.c +++ b/test/Sema/const-eval.c @@ -66,3 +66,5 @@ EVAL_EXPR(30, (int)(_Complex float)((1<<30)-1) == (1<<30) ? 1 : -1) EVAL_EXPR(31, (int*)0 == (int*)0 ? 1 : -1) EVAL_EXPR(32, (int*)0 != (int*)0 ? -1 : 1) EVAL_EXPR(33, (void*)0 - (void*)0 == 0 ? 1 : -1) +void foo(void) {} +EVAL_EXPR(34, (foo == (void *)0) ? -1 : 1)