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:
parent
16a2a45880
commit
7482d5a3ac
@ -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;
|
||||
|
||||
32
gcc/testsuite/g++.dg/cpp0x/enum41.C
Normal file
32
gcc/testsuite/g++.dg/cpp0x/enum41.C
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user