From 9e36b533af1b2fa9f32c4372c4081abdd86f47e0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 31 Oct 2011 05:11:32 +0000 Subject: [PATCH] C++11 generalized constant expressions: evaluate equality comparisons between arbitrary pointers, if those pointers don't point to weak objects or literals. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143334 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 80 ++++++++++++---------- test/SemaCXX/constant-expression-cxx11.cpp | 16 +++-- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ee89529176..f4c9a8336c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -257,6 +257,39 @@ static bool CheckConstantExpression(const CCValue &Value) { return !Value.isLValue() || IsGlobalLValue(Value.getLValueBase()); } +const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { + if (!LVal.Base) + return 0; + + if (const DeclRefExpr *DRE = dyn_cast(LVal.Base)) + return 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(LVal.Base)) { + assert(!isa(ME->getMemberDecl()) && "shouldn't see fields here"); + return ME->getMemberDecl(); + } + + return 0; +} + +static bool IsLiteralLValue(const LValue &Value) { + return Value.Base && + !isa(Value.Base) && + !isa(Value.Base); +} + +static bool IsWeakLValue(const LValue &Value) { + const ValueDecl *Decl = GetLValueBaseDecl(Value); + if (!Decl) + return false; + + return Decl->hasAttr() || + Decl->hasAttr() || + Decl->isWeakImported(); +} + static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { const Expr* Base = Value.Base; @@ -275,19 +308,7 @@ static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) { // be true, but if it'a decl-ref to a weak symbol it can be null at // runtime. Result = true; - - const DeclRefExpr* DeclRef = dyn_cast(Base); - if (!DeclRef) - return true; - - // If it's a weak symbol, it isn't constant-evaluable. - const ValueDecl* Decl = DeclRef->getDecl(); - if (Decl->hasAttr() || - Decl->hasAttr() || - Decl->isWeakImported()) - return false; - - return true; + return !IsWeakLValue(Value); } static bool HandleConversionToBool(const CCValue &Val, bool &Result) { @@ -417,23 +438,6 @@ static bool IsConstNonVolatile(QualType T) { return Quals.hasConst() && !Quals.hasVolatile(); } -const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { - if (!LVal.Base) - return 0; - - if (const DeclRefExpr *DRE = dyn_cast(LVal.Base)) - return 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(LVal.Base)) { - assert(!isa(ME->getMemberDecl()) && "shouldn't see fields here"); - return ME->getMemberDecl(); - } - - return 0; -} - bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, const LValue &LVal, CCValue &RVal) { const Expr *Base = LVal.Base; @@ -1925,16 +1929,20 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + // Inequalities and subtractions between unrelated pointers have + // unspecified or undefined behavior. if (!E->isEqualityOp()) return false; - if ((LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())&& - (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())) + // It's implementation-defined whether distinct literals will have + // distinct addresses. We define it to be unspecified. + if (IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) return false; - LValue &NonNull = LHSValue.getLValueBase() ? LHSValue : RHSValue; - bool bres; - if (!EvalPointerValueAsBool(NonNull, bres)) + // We can't tell whether weak symbols will end up pointing to the same + // object. + if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) return false; - return Success(bres ^ (E->getOpcode() == BO_EQ), E); + // Pointers with different bases cannot represent the same object. + return Success(E->getOpcode() == BO_NE, E); } if (E->getOpcode() == BO_Sub) { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 9f9c36bc5e..b02253cf45 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -161,8 +161,8 @@ namespace FunctionPointers { namespace PointerComparison { int x, y; -constexpr bool g1 = &x == &y; // expected-error {{must be initialized by a constant expression}} -constexpr bool g2 = &x != &y; // expected-error {{must be initialized by a constant expression}} +constexpr bool g1 = &x == &y; +constexpr bool g2 = &x != &y; constexpr bool g3 = &x <= &y; // expected-error {{must be initialized by a constant expression}} constexpr bool g4 = &x >= &y; // expected-error {{must be initialized by a constant expression}} constexpr bool g5 = &x < &y; // expected-error {{must be initialized by a constant expression}} @@ -190,8 +190,16 @@ constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a const constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}} constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}} +constexpr bool s1 = &x == &x; +constexpr bool s2 = &x != &x; +constexpr bool s3 = &x <= &x; +constexpr bool s4 = &x >= &x; +constexpr bool s5 = &x < &x; +constexpr bool s6 = &x > &x; + using check = int[m1 + (m2<<1) + (m3<<2) + (m4<<3) + (m5<<4) + (m6<<5) + - (n1<<6) + (n2<<7) + (n7<<8) + (n8<<9)]; -using check = int[2+4+16+128+512]; + (n1<<6) + (n2<<7) + (n7<<8) + (n8<<9) + (g1<<10) + (g2<<11) + + (s1<<12) + (s2<<13) + (s3<<14) + (s4<<15) + (s5<<16) + (s6<<17)]; +using check = int[2+4+16+128+512+2048+4096+16384+32768]; } -- 2.40.0