c++: ICE with switch and scoped enum bit-fields [PR98043]

In this testcase we are crashing trying to gimplify a switch, because
the types of the switch condition and case constants have different
TYPE_PRECISIONs.

This started with my r5-3726 fix: SWITCH_STMT_TYPE is supposed to be the
original type of the switch condition before any conversions, so in the
C++ FE we need to use unlowered_expr_type to get the unlowered type of
enum bit-fields.

Normally, the switch type is subject to integral promotions, but here
we have a scoped enum type and those don't promote:

  enum class B { A };
  struct C { B c : 8; };

  switch (x.c) // type B
    case B::A: // type int, will be converted to B

Here TREE_TYPE is "signed char" but SWITCH_STMT_TYPE is "B".  When
gimplifying this in gimplify_switch_expr, the index type is "B" and
we convert all the case values to "B" in preprocess_case_label_vec,
but SWITCH_COND is of type "signed char": gimple_switch_index should
be the (possibly promoted) type, not the original type, so we gimplify
the "x.c" SWITCH_COND to a SSA_NAME of type "signed char".  And then
we crash because the precision of the index type doesn't match the
precision of the case value type.

I think it makes sense to do the following; at the end of pop_switch
we've already issued the switch warnings, and since scoped enums don't
promote, it should be okay to use the type of SWITCH_STMT_COND.  The
r5-3726 change was about giving warnings for enum bit-fields anyway.

gcc/cp/ChangeLog:

	PR c++/98043
	* decl.c (pop_switch): If SWITCH_STMT_TYPE is a scoped enum type,
	set it to the type of SWITCH_STMT_COND.

gcc/testsuite/ChangeLog:

	PR c++/98043
	* g++.dg/cpp0x/enum41.C: New test.
This commit is contained in:
Marek Polacek 2020-12-02 10:47:49 -05:00
parent 16a2a45880
commit 7482d5a3ac
2 changed files with 45 additions and 4 deletions

View File

@ -3690,17 +3690,17 @@ void
pop_switch (void)
{
struct cp_switch *cs = switch_stack;
location_t switch_location;
/* Emit warnings as needed. */
switch_location = cp_expr_loc_or_input_loc (cs->switch_stmt);
location_t switch_location = cp_expr_loc_or_input_loc (cs->switch_stmt);
tree cond = SWITCH_STMT_COND (cs->switch_stmt);
const bool bool_cond_p
= (SWITCH_STMT_TYPE (cs->switch_stmt)
&& TREE_CODE (SWITCH_STMT_TYPE (cs->switch_stmt)) == BOOLEAN_TYPE);
if (!processing_template_decl)
c_do_switch_warnings (cs->cases, switch_location,
SWITCH_STMT_TYPE (cs->switch_stmt),
SWITCH_STMT_COND (cs->switch_stmt), bool_cond_p);
SWITCH_STMT_TYPE (cs->switch_stmt), cond,
bool_cond_p);
/* For the benefit of block_may_fallthru remember if the switch body
case labels cover all possible values and if there are break; stmts. */
@ -3711,6 +3711,15 @@ pop_switch (void)
SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1;
if (!cs->break_stmt_seen_p)
SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = 1;
/* Now that we're done with the switch warnings, set the switch type
to the type of the condition if the index type was of scoped enum type.
(Such types don't participate in the integer promotions.) We do this
because of bit-fields whose declared type is a scoped enum type:
gimplification will use the lowered index type, but convert the
case values to SWITCH_STMT_TYPE, which would have been the declared type
and verify_gimple_switch doesn't accept that. */
if (is_bitfield_expr_with_lowered_type (cond))
SWITCH_STMT_TYPE (cs->switch_stmt) = TREE_TYPE (cond);
gcc_assert (!cs->in_loop_body_p);
splay_tree_delete (cs->cases);
switch_stack = switch_stack->next;

View File

@ -0,0 +1,32 @@
// PR c++/98043
// { dg-do compile { target c++11 } }
enum class B { A };
struct C { B c : 8; };
bool
foo (C x)
{
switch (x.c)
{
case B::A:
return false;
default:
return true;
}
}
enum E { X };
struct D { E c : 7; };
bool
bar (D x)
{
switch (x.c)
{
case E::X:
return false;
default:
return true;
}
}