On Wed, Dec 02, 2020 at 09:50:33PM -0500, Jason Merrill wrote:
> On 12/2/20 6:18 PM, Marek Polacek wrote:
> > 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.
> > 
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?
> > 
> > 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.
> 
> It might make sense to do this in cp_genericize_r instead, but here is fine.

Right.  In the end I chose pop_switch due to the other SWITCH_STMT_* handling,
so that it's in the same function.

> > --- a/gcc/cp/decl.c
> > +++ b/gcc/cp/decl.c
> > @@ -3711,6 +3711,17 @@ 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 (SWITCH_STMT_TYPE (cs->switch_stmt)
> > +      && SCOPED_ENUM_P (SWITCH_STMT_TYPE (cs->switch_stmt)))
> > +    SWITCH_STMT_TYPE (cs->switch_stmt)
> > +      = TREE_TYPE (SWITCH_STMT_COND (cs->switch_stmt));
> 
> What would be the impact of doing this for all
> is_bitfield_expr_with_lowered_type conditions, rather than all scoped enum
> conditions?

The impact is the same: for ordinary bit-fields and unscoped enum bit-fields,
cond will already have been promoted here, so e.g. "(int) a.b", and
is_bitfield_expr_with_lowered_type will return NULL_TREE.  And for scoped
enum bit-fields we will do the same thing as in v1.  I think the SCOPED_ENUM_P
check is cheaper than is_bitfield_expr_with_lowered_type but I'm fine with
either version.  Thanks,

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?

-- >8 --
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.
---
 gcc/cp/decl.c                       | 17 +++++++++++----
 gcc/testsuite/g++.dg/cpp0x/enum41.C | 32 +++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum41.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index a28e7924869..7da8c65e984 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum41.C 
b/gcc/testsuite/g++.dg/cpp0x/enum41.C
new file mode 100644
index 00000000000..5f6ef13289b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum41.C
@@ -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;
+    }
+}

base-commit: df933e307b1950ce12472660dcac1765b8eb431d
-- 
2.28.0

Reply via email to