[cfe-commits] r143329 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Sun Oct 30 18:37:14 PDT 2011
Author: rsmith
Date: Sun Oct 30 20:37:14 2011
New Revision: 143329
URL: http://llvm.org/viewvc/llvm-project?rev=143329&view=rev
Log:
C++11 generalized constant expressions: support pointer comparisons where the
result is not unspecified.
Modified:
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143329&r1=143328&r2=143329&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Oct 30 20:37:14 2011
@@ -195,9 +195,10 @@
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 @@
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 @@
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 @@
}
}
+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 @@
}
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 @@
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 @@
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() ||
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143329&r1=143328&r2=143329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sun Oct 30 20:37:14 2011
@@ -157,3 +157,41 @@
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];
+
+}
More information about the cfe-commits
mailing list