Commit 47518e13 by Jason Merrill Committed by Jason Merrill

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
parent a4d034d7
2019-09-15 Jason Merrill <jason@redhat.com> 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 * 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 the operands of a built-in operator. Don't suppress conversions in
cp_build_unary_op. cp_build_unary_op.
......
...@@ -5815,6 +5815,9 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, ...@@ -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 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); arg1 = prep_operand (arg1);
bool memonly = false; bool memonly = false;
...@@ -5846,8 +5849,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, ...@@ -5846,8 +5849,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
case EQ_EXPR: case EQ_EXPR:
case NE_EXPR: case NE_EXPR:
/* These are saved for the sake of maybe_warn_bool_compare. */ /* These are saved for the sake of maybe_warn_bool_compare. */
code_orig_arg1 = TREE_CODE (TREE_TYPE (arg1)); code_orig_arg1 = TREE_CODE (arg1_type);
code_orig_arg2 = TREE_CODE (TREE_TYPE (arg2)); code_orig_arg2 = TREE_CODE (arg2_type);
break; break;
/* =, ->, [], () must be non-static member functions. */ /* =, ->, [], () 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, ...@@ -5870,8 +5873,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
if (code == COND_EXPR) if (code == COND_EXPR)
/* Use build_conditional_expr instead. */ /* Use build_conditional_expr instead. */
gcc_unreachable (); gcc_unreachable ();
else if (! OVERLOAD_TYPE_P (TREE_TYPE (arg1)) else if (! OVERLOAD_TYPE_P (arg1_type)
&& (! arg2 || ! OVERLOAD_TYPE_P (TREE_TYPE (arg2)))) && (! arg2 || ! OVERLOAD_TYPE_P (arg2_type)))
goto builtin; goto builtin;
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) 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, ...@@ -5903,11 +5906,11 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
args[2] = NULL_TREE; args[2] = NULL_TREE;
/* Add class-member operators to the candidate set. */ /* Add class-member operators to the candidate set. */
if (CLASS_TYPE_P (TREE_TYPE (arg1))) if (CLASS_TYPE_P (arg1_type))
{ {
tree fns; tree fns;
fns = lookup_fnfields (TREE_TYPE (arg1), fnname, 1); fns = lookup_fnfields (arg1_type, fnname, 1);
if (fns == error_mark_node) if (fns == error_mark_node)
{ {
result = 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, ...@@ -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 has an enumeration type, or T2 or reference to cv-qualified-opt
T2 for the second argument, if the second argument has an T2 for the second argument, if the second argument has an
enumeration type. Filter out those that don't match. */ 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; struct z_candidate **candp, **next;
...@@ -5947,9 +5950,9 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, ...@@ -5947,9 +5950,9 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
if (TYPE_REF_P (parmtype)) if (TYPE_REF_P (parmtype))
parmtype = TREE_TYPE (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 && (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (args[i]), parmtype))) (unlowered_expr_type (args[i]), parmtype)))
break; break;
parmlist = TREE_CHAIN (parmlist); parmlist = TREE_CHAIN (parmlist);
...@@ -6124,15 +6127,15 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, ...@@ -6124,15 +6127,15 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
case LE_EXPR: case LE_EXPR:
case EQ_EXPR: case EQ_EXPR:
case NE_EXPR: case NE_EXPR:
if (TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE if (TREE_CODE (arg1_type) == ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE && TREE_CODE (arg2_type) == ENUMERAL_TYPE
&& (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) && (TYPE_MAIN_VARIANT (arg1_type)
!= TYPE_MAIN_VARIANT (TREE_TYPE (arg2))) != TYPE_MAIN_VARIANT (arg2_type))
&& (complain & tf_warning)) && (complain & tf_warning))
{ {
warning (OPT_Wenum_compare, warning (OPT_Wenum_compare,
"comparison between %q#T and %q#T", "comparison between %q#T and %q#T",
TREE_TYPE (arg1), TREE_TYPE (arg2)); arg1_type, arg2_type);
} }
break; break;
default: default:
......
// 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"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment