From 9b0607def49d8e30128253635ec44771f7c03530 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 11 Jun 2018 17:01:23 -0400 Subject: [PATCH] Fix ptrmem comparison for unions. * constexpr.c (cxx_eval_binary_expression): Special case comparison of pointers to members of the same union. From-SVN: r261454 --- gcc/cp/ChangeLog | 5 +++++ gcc/cp/constexpr.c | 18 ++++++++++++++++-- gcc/testsuite/g++.dg/expr/ptrmem10.C | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/expr/ptrmem10.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 595a08f3d44..4c7041b6cc4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2018-06-05 Jason Merrill + + * constexpr.c (cxx_eval_binary_expression): Special case comparison + of pointers to members of the same union. + 2018-06-11 Jason Merrill PR c++/86094 - wrong code with defaulted move ctor. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 944c1cdf11e..97a338535db 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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 index 00000000000..71d2df85860 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/ptrmem10.C @@ -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)); +} -- 2.30.2