diff options
-rw-r--r-- | lib/AST/ExprConstant.cpp | 101 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 38 |
2 files changed, 99 insertions, 40 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index bf428aaacc..ee89529176 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -195,9 +195,10 @@ namespace { CharUnits Offset; unsigned CallIndex; - const Expr *getLValueBase() { return Base; } + const Expr *getLValueBase() const { return Base; } CharUnits &getLValueOffset() { return Offset; } - unsigned getLValueCallIndex() { return CallIndex; } + const CharUnits &getLValueOffset() const { return Offset; } + unsigned getLValueCallIndex() const { return CallIndex; } void moveInto(CCValue &V) const { V = CCValue(Base, Offset, CallIndex); @@ -416,6 +417,23 @@ 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<DeclRefExpr>(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<MemberExpr>(LVal.Base)) { + assert(!isa<FieldDecl>(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; @@ -431,26 +449,12 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, if (!LVal.Offset.isZero()) return false; - const Decl *D = 0; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const ValueDecl *D = GetLValueBaseDecl(LVal)) { // 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 (!Info.Ctx.hasSameUnqualifiedType(Type, D->getType())) + return 0; - 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. Inside constexpr functions, @@ -1767,6 +1771,25 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } } +static bool HasSameBase(const LValue &A, const LValue &B) { + if (!A.getLValueBase()) + return !B.getLValueBase(); + if (!B.getLValueBase()) + return false; + + if (A.getLValueBase() != B.getLValueBase()) { + const Decl *ADecl = GetLValueBaseDecl(A); + if (!ADecl) + return false; + const Decl *BDecl = GetLValueBaseDecl(B); + if (ADecl != BDecl) + return false; + } + + return IsGlobalLValue(A.getLValueBase()) || + A.getLValueCallIndex() == B.getLValueCallIndex(); +} + bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->isAssignmentOp()) return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); @@ -1890,7 +1913,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - if (E->getOpcode() == BO_Sub || E->isEqualityOp()) { + if (E->getOpcode() == BO_Sub || E->isComparisonOp()) { LValue LHSValue; if (!EvaluatePointer(E->getLHS(), LHSValue, Info)) return false; @@ -1899,24 +1922,17 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) return false; - // Reject any bases from the normal codepath; we special-case comparisons - // to null. - if (LHSValue.getLValueBase()) { + // Reject differing bases from the normal codepath; we special-case + // comparisons to null. + if (!HasSameBase(LHSValue, RHSValue)) { if (!E->isEqualityOp()) return false; - if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero()) + if ((LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())&& + (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())) return false; + LValue &NonNull = LHSValue.getLValueBase() ? LHSValue : RHSValue; bool bres; - if (!EvalPointerValueAsBool(LHSValue, bres)) - return false; - return Success(bres ^ (E->getOpcode() == BO_EQ), E); - } else if (RHSValue.getLValueBase()) { - if (!E->isEqualityOp()) - return false; - if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero()) - return false; - bool bres; - if (!EvalPointerValueAsBool(RHSValue, bres)) + if (!EvalPointerValueAsBool(NonNull, bres)) return false; return Success(bres ^ (E->getOpcode() == BO_EQ), E); } @@ -1933,13 +1949,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { RHSValue.getLValueOffset(); return Success(Diff / ElementSize, E); } - bool Result; - if (E->getOpcode() == BO_EQ) { - Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset(); - } else { - Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset(); + + const CharUnits &LHSOffset = LHSValue.getLValueOffset(); + const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + switch (E->getOpcode()) { + default: llvm_unreachable("missing comparison operator"); + case BO_LT: return Success(LHSOffset < RHSOffset, E); + case BO_GT: return Success(LHSOffset > RHSOffset, E); + case BO_LE: return Success(LHSOffset <= RHSOffset, E); + case BO_GE: return Success(LHSOffset >= RHSOffset, E); + case BO_EQ: return Success(LHSOffset == RHSOffset, E); + case BO_NE: return Success(LHSOffset != RHSOffset, E); } - return Success(Result, E); } } if (!LHSTy->isIntegralOrEnumerationType() || diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 57e6e2fce2..9f9c36bc5e 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -157,3 +157,41 @@ namespace FunctionPointers { constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} } + +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 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}} +constexpr bool g6 = &x > &y; // expected-error {{must be initialized by a constant expression}} + +struct S { int x, y; } s; +constexpr bool m1 = &s.x == &s.y; +constexpr bool m2 = &s.x != &s.y; +constexpr bool m3 = &s.x <= &s.y; +constexpr bool m4 = &s.x >= &s.y; +constexpr bool m5 = &s.x < &s.y; +constexpr bool m6 = &s.x > &s.y; + +constexpr bool n1 = 0 == &y; +constexpr bool n2 = 0 != &y; +constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}} +constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}} +constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}} +constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}} + +constexpr bool n7 = &x == 0; +constexpr bool n8 = &x != 0; +constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}} +constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}} +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}} + +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]; + +} |