This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH 3/4] PR c++/82165 - enum bitfields and operator overloading.
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 16 Sep 2019 00:33:27 -0400
- Subject: [C++ PATCH 3/4] PR c++/82165 - enum bitfields and operator overloading.
- References: <20190916043328.3739-1-jason@redhat.com>
In this testcase, !f.b0 was failing to call the overloaded operator because
TREE_TYPE is the magic bitfield integer type, and we weren't using
unlowered_expr_type the way we do in other places. It would be nice if we
could give bit-field COMPONENT_REFs their declared type until genericization
time...
Tested x86_64-pc-linux-gnu, applying to trunk.
* call.c (build_new_op_1): Use unlowered_expr_type.
---
gcc/cp/call.c | 31 ++++++++++++----------
gcc/testsuite/g++.dg/expr/bitfield13.C | 36 ++++++++++++++++++++++++++
gcc/cp/ChangeLog | 3 +++
3 files changed, 56 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/expr/bitfield13.C
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 457fa6605c2..b780b0af58e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5815,6 +5815,9 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
}
tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code);
+ tree arg1_type = unlowered_expr_type (arg1);
+ tree arg2_type = arg2 ? unlowered_expr_type (arg2) : NULL_TREE;
+
arg1 = prep_operand (arg1);
bool memonly = false;
@@ -5846,8 +5849,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
case EQ_EXPR:
case NE_EXPR:
/* These are saved for the sake of maybe_warn_bool_compare. */
- code_orig_arg1 = TREE_CODE (TREE_TYPE (arg1));
- code_orig_arg2 = TREE_CODE (TREE_TYPE (arg2));
+ code_orig_arg1 = TREE_CODE (arg1_type);
+ code_orig_arg2 = TREE_CODE (arg2_type);
break;
/* =, ->, [], () must be non-static member functions. */
@@ -5870,8 +5873,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
if (code == COND_EXPR)
/* Use build_conditional_expr instead. */
gcc_unreachable ();
- else if (! OVERLOAD_TYPE_P (TREE_TYPE (arg1))
- && (! arg2 || ! OVERLOAD_TYPE_P (TREE_TYPE (arg2))))
+ else if (! OVERLOAD_TYPE_P (arg1_type)
+ && (! arg2 || ! OVERLOAD_TYPE_P (arg2_type)))
goto builtin;
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
@@ -5903,11 +5906,11 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
args[2] = NULL_TREE;
/* Add class-member operators to the candidate set. */
- if (CLASS_TYPE_P (TREE_TYPE (arg1)))
+ if (CLASS_TYPE_P (arg1_type))
{
tree fns;
- fns = lookup_fnfields (TREE_TYPE (arg1), fnname, 1);
+ fns = lookup_fnfields (arg1_type, fnname, 1);
if (fns == error_mark_node)
{
result = error_mark_node;
@@ -5927,7 +5930,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
has an enumeration type, or T2 or reference to cv-qualified-opt
T2 for the second argument, if the second argument has an
enumeration type. Filter out those that don't match. */
- else if (! arg2 || ! CLASS_TYPE_P (TREE_TYPE (arg2)))
+ else if (! arg2 || ! CLASS_TYPE_P (arg2_type))
{
struct z_candidate **candp, **next;
@@ -5947,9 +5950,9 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
if (TYPE_REF_P (parmtype))
parmtype = TREE_TYPE (parmtype);
- if (TREE_CODE (TREE_TYPE (args[i])) == ENUMERAL_TYPE
+ if (TREE_CODE (unlowered_expr_type (args[i])) == ENUMERAL_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (args[i]), parmtype)))
+ (unlowered_expr_type (args[i]), parmtype)))
break;
parmlist = TREE_CHAIN (parmlist);
@@ -6124,15 +6127,15 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
- if (TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE
- && TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE
- && (TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
- != TYPE_MAIN_VARIANT (TREE_TYPE (arg2)))
+ if (TREE_CODE (arg1_type) == ENUMERAL_TYPE
+ && TREE_CODE (arg2_type) == ENUMERAL_TYPE
+ && (TYPE_MAIN_VARIANT (arg1_type)
+ != TYPE_MAIN_VARIANT (arg2_type))
&& (complain & tf_warning))
{
warning (OPT_Wenum_compare,
"comparison between %q#T and %q#T",
- TREE_TYPE (arg1), TREE_TYPE (arg2));
+ arg1_type, arg2_type);
}
break;
default:
diff --git a/gcc/testsuite/g++.dg/expr/bitfield13.C b/gcc/testsuite/g++.dg/expr/bitfield13.C
new file mode 100644
index 00000000000..3f57d5f0397
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/bitfield13.C
@@ -0,0 +1,36 @@
+// PR c++/82165
+// { dg-do compile { target c++11 } }
+
+struct flags {
+ enum field { f0, f1, no_field };
+ field b0 : 4;
+ field b1 : 4;
+ field a0, a1;
+};
+
+constexpr bool operator!(flags::field f) {
+ return f == flags::no_field;
+}
+
+#define SA(X) static_assert ((X), #X)
+
+int main() {
+ constexpr flags f { flags::f0, flags::f1, flags::f0, flags::f1 };
+
+ SA( flags::f0 == 0 ); // 0
+ SA( flags::f1 == 1 ); // 1
+ SA( flags::no_field == 2 ); // 2
+ SA( !flags::f0 == 0 ); // (!) 0
+ SA( !flags::f1 == 0 ); // (!) 0
+ SA( !flags::no_field == 1 ); // (!) 1
+
+ SA( f.a0 == 0 ); // 0
+ SA( f.a1 == 1 ); // 1
+ SA( !f.a0 == 0 ); // (!) 0
+ SA( !f.a1 == 0 ); // (!) 0
+
+ SA( f.b0 == 0 ); // 0
+ SA( f.b1 == 1 ); // 1
+ SA( !f.b0 == 0 ); // expected "(!) 0", but got "1"
+ SA( !f.b1 == 0 ); // expected "(!) 0", but got "0"
+}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a03a428109b..bed72c90a2e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,8 @@
2019-09-15 Jason Merrill <jason@redhat.com>
+ PR c++/82165 - enum bitfields and operator overloading.
+ * call.c (build_new_op_1): Use unlowered_expr_type.
+
* call.c (build_new_op_1): Don't apply any standard conversions to
the operands of a built-in operator. Don't suppress conversions in
cp_build_unary_op.
--
2.21.0