aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td2
-rw-r--r--lib/AST/ExprConstant.cpp12
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp13
3 files changed, 26 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 9fe22ad3ba..1cdbcb962e 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -53,6 +53,8 @@ def note_constexpr_var_init_non_constant : Note<
def note_constexpr_typeid_polymorphic : Note<
"typeid applied to expression of polymorphic type %0 is "
"not allowed in a constant expression">;
+def note_constexpr_void_comparison : Note<
+ "comparison between unequal pointers to void has unspecified result">;
def note_constexpr_temporary_here : Note<"temporary created here">;
def note_constexpr_literal_here : Note<"literal written here">;
def note_constexpr_depth_limit_exceeded : Note<
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c038e3feae..5a385e6eb4 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -4331,6 +4331,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
const CharUnits &LHSOffset = LHSValue.getLValueOffset();
const CharUnits &RHSOffset = RHSValue.getLValueOffset();
+
+ // C++11 [expr.rel]p3:
+ // Pointers to void (after pointer conversions) can be compared, with a
+ // result defined as follows: If both pointers represent the same
+ // address or are both the null pointer value, the result is true if the
+ // operator is <= or >= and false otherwise; otherwise the result is
+ // unspecified.
+ // We interpret this as applying to pointers to *cv* void.
+ if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset &&
+ E->getOpcode() != BO_EQ && E->getOpcode() != BO_NE)
+ CCEDiag(E, diag::note_constexpr_void_comparison);
+
switch (E->getOpcode()) {
default: llvm_unreachable("missing comparison operator");
case BO_LT: return Success(LHSOffset < RHSOffset, E);
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index a39de4d2b9..617edc5faa 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -376,10 +376,21 @@ namespace UnspecifiedRelations {
// If two pointers point to non-static data members of the same object with
// different access control, the result is unspecified.
- // FIXME:
// [expr.rel]p3: Pointers to void can be compared [...] if both pointers
// represent the same address or are both the null pointer [...]; otherwise
// the result is unspecified.
+ struct S { int a, b; } s;
+ constexpr void *null = 0;
+ constexpr void *pv = (void*)&s.a;
+ constexpr void *qv = (void*)&s.b;
+ constexpr bool v1 = null < 0;
+ constexpr bool v2 = null < pv; // expected-error {{constant expression}}
+ constexpr bool v3 = null == pv; // ok
+ constexpr bool v4 = qv == pv; // ok
+ constexpr bool v5 = qv >= pv; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
+ constexpr bool v6 = qv > null; // expected-error {{constant expression}}
+ constexpr bool v7 = qv <= (void*)&s.b; // ok
+ constexpr bool v8 = qv > (void*)&s.a; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
// FIXME: Implement comparisons of pointers to members.
// [expr.eq]p2: If either is a pointer to a virtual member function and