From 47518e131f299f69d0c14f7e5efe83609185ed9f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 16 Sep 2019 00:34:23 -0400 Subject: [PATCH] PR c++/82165 - enum bitfields and operator overloading. 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... * call.c (build_new_op_1): Use unlowered_expr_type. From-SVN: r275745 --- gcc/cp/ChangeLog | 3 +++ gcc/cp/call.c | 31 ++++++++++++---------- gcc/testsuite/g++.dg/expr/bitfield13.C | 36 ++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/expr/bitfield13.C 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 + 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. 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" +} -- 2.30.2