8sa1-gcc/gcc/testsuite/g++.dg/cpp0x/enum41.C
Marek Polacek 7482d5a3ac 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.
2020-12-07 12:38:01 -05:00

33 lines
364 B
C

// 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;
}
}