Fix ptrmem comparison for unions.
authorJason Merrill <jason@redhat.com>
Mon, 11 Jun 2018 21:01:23 +0000 (17:01 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 11 Jun 2018 21:01:23 +0000 (17:01 -0400)
* constexpr.c (cxx_eval_binary_expression): Special case comparison
of pointers to members of the same union.

From-SVN: r261454

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/expr/ptrmem10.C [new file with mode: 0644]

index 595a08f3d448132b7fc91b2d5ad8f575b3fdb5e5..4c7041b6cc416c10311f402432b8910203875be8 100644 (file)
@@ -1,3 +1,8 @@
+2018-06-05  Jason Merrill  <jason@redhat.com>
+
+       * constexpr.c (cxx_eval_binary_expression): Special case comparison
+       of pointers to members of the same union.
+
 2018-06-11  Jason Merrill  <jason@redhat.com>
 
        PR c++/86094 - wrong code with defaulted move ctor.
index 944c1cdf11ecf934b40ed7667bac7afaca388f86..97a338535db764a3a5cb3db0cd0dd8596f2bb69f 100644 (file)
@@ -2051,8 +2051,22 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 
       if (TREE_CODE (lhs) == PTRMEM_CST
          && TREE_CODE (rhs) == PTRMEM_CST)
-       r = constant_boolean_node (cp_tree_equal (lhs, rhs) == is_code_eq,
-                                  type);
+       {
+         tree lmem = PTRMEM_CST_MEMBER (lhs);
+         tree rmem = PTRMEM_CST_MEMBER (rhs);
+         bool eq;
+         if (TREE_CODE (lmem) == TREE_CODE (rmem)
+             && TREE_CODE (lmem) == FIELD_DECL
+             && TREE_CODE (DECL_CONTEXT (lmem)) == UNION_TYPE
+             && same_type_p (DECL_CONTEXT (lmem),
+                             DECL_CONTEXT (rmem)))
+           /* If both refer to (possibly different) members of the same union
+              (12.3), they compare equal. */
+           eq = true;
+         else
+           eq = cp_tree_equal (lhs, rhs);
+         r = constant_boolean_node (eq == is_code_eq, type);
+       }
       else if ((TREE_CODE (lhs) == PTRMEM_CST
                || TREE_CODE (rhs) == PTRMEM_CST)
               && (null_member_pointer_value_p (lhs)
diff --git a/gcc/testsuite/g++.dg/expr/ptrmem10.C b/gcc/testsuite/g++.dg/expr/ptrmem10.C
new file mode 100644 (file)
index 0000000..71d2df8
--- /dev/null
@@ -0,0 +1,28 @@
+/* [expr.eq] If both refer to (possibly different) members of the same union
+   (12.3), they compare equal. */
+// { dg-do run { target c++11 } }
+// { dg-additional-options -O }
+
+union U
+{
+  int i;
+  int j;
+};
+
+#define SA(X) static_assert ((X),#X)
+SA (&U::i == &U::j);
+SA (!(&U::i != &U::j));
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
+
+void f (int U::*p, int U::*q)
+{
+  assert (p==q);
+  assert (!(p!=q));
+}
+
+int main()
+{
+  assert (&U::i == &U::j);
+  assert (!(&U::i != &U::j));
+}