]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
inline-asm: Fix ICE with bitfields in "m" operands [PR100785]
authorJakub Jelinek <jakub@redhat.com>
Mon, 21 Jun 2021 11:30:42 +0000 (13:30 +0200)
committerJakub Jelinek <jakub@redhat.com>
Mon, 21 Jun 2021 11:32:36 +0000 (13:32 +0200)
Bitfields, while they live in memory, aren't something inline-asm can easily
operate on.
For C and "=m" or "+m", we were diagnosing bitfields in the past in the
FE, where c_mark_addressable had:
      case COMPONENT_REF:
        if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
          {
            error
              ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1));
            return false;
          }
but that check got moved in GCC 6 to build_unary_op instead and now we
emit an error during expansion and ICE afterwards (i.e. error-recovery).
For "m" it used to be diagnosed in c_mark_addressable too, but since
GCC 6 it is ice-on-invalid.
For C++, this was never diagnosed in the FE, but used to be diagnosed
in the gimplifier and/or during expansion before 4.8.

The following patch does multiple things:
1) diagnoses it in the FEs
2) stops emitting a redundant diagnostic in the gimplifier using the
   usual way, if we already see error_mark_node, we assume error has
   been emitted already and only diagnose if it wasn't error_mark_node;
   this helps diagnosing the same bug with multiple different
   errors
3) simplifies during expansion the inline asm if any errors have been
   reported (similarly how e.g. vregs pass if it detects errors on
   inline-asm either deletes them or simplifies to bare minimum -
   just labels), so that we don't have error-recovery ICEs there

2021-06-11  Jakub Jelinek  <jakub@redhat.com>

PR inline-asm/100785
gcc/
* gimplify.c (gimplify_asm_expr): Don't diagnose errors if
output or input operands were already error_mark_node.
* cfgexpand.c (expand_asm_stmt): If errors are emitted,
remove all inputs, outputs and clobbers from the asm and
set template to "".
gcc/c/
* c-typeck.c (c_mark_addressable): Diagnose trying to make
bit-fields addressable.
gcc/cp/
* typeck.c (cxx_mark_addressable): Diagnose trying to make
bit-fields addressable.
gcc/testsuite/
* c-c++-common/pr100785.c: New test.
* gcc.dg/pr48552-1.c: Don't expect invalid lvalue errors.
* gcc.dg/pr48552-2.c: Likewise.

gcc/c/c-typeck.c
gcc/cfgexpand.c
gcc/cp/typeck.c
gcc/gimplify.c
gcc/testsuite/c-c++-common/pr100785.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr48552-1.c
gcc/testsuite/gcc.dg/pr48552-2.c

index 845d50f3310d7d46f13cbc6bbd57ddfbbdffaa15..77de881c14ad448803d386aa27f1624eb7d440f1 100644 (file)
@@ -5034,8 +5034,17 @@ c_mark_addressable (tree exp, bool array_ref_p)
            && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
            && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
          return true;
-       /* FALLTHRU */
+       x = TREE_OPERAND (x, 0);
+       break;
+
       case COMPONENT_REF:
+       if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+         {
+           error ("cannot take address of bit-field %qD",
+                  TREE_OPERAND (x, 1));
+           return false;
+         }
+       /* FALLTHRU */
       case ADDR_EXPR:
       case ARRAY_REF:
       case REALPART_EXPR:
index 39e5b04042704fbe89b4e60250302d0a78fb4045..6394cfdcb5611265cbba44b969c4e497ef55dd08 100644 (file)
@@ -3082,6 +3082,7 @@ expand_asm_stmt (gasm *stmt)
   unsigned ninputs = gimple_asm_ninputs (stmt);
   unsigned nlabels = gimple_asm_nlabels (stmt);
   unsigned i;
+  bool error_seen = false;
 
   /* ??? Diagnose during gimplification?  */
   if (ninputs + noutputs + nlabels > MAX_RECOG_OPERANDS)
@@ -3140,6 +3141,7 @@ expand_asm_stmt (gasm *stmt)
                {
                  /* ??? Diagnose during gimplification?  */
                  error ("unknown register name %qs in %<asm%>", regname);
+                 error_seen = true;
                }
              else if (j == -4)
                {
@@ -3202,7 +3204,10 @@ expand_asm_stmt (gasm *stmt)
                && REG_P (DECL_RTL (output_tvec[j]))
                && HARD_REGISTER_P (DECL_RTL (output_tvec[j]))
                && output_hregno == REGNO (DECL_RTL (output_tvec[j])))
-             error ("invalid hard register usage between output operands");
+             {
+               error ("invalid hard register usage between output operands");
+               error_seen = true;
+             }
 
          /* Verify matching constraint operands use the same hard register
             and that the non-matching constraint operands do not use the same
@@ -3225,13 +3230,19 @@ expand_asm_stmt (gasm *stmt)
                  }
                if (i == match
                    && output_hregno != input_hregno)
-                 error ("invalid hard register usage between output operand "
-                        "and matching constraint operand");
+                 {
+                   error ("invalid hard register usage between output "
+                          "operand and matching constraint operand");
+                   error_seen = true;
+                 }
                else if (early_clobber_p
                         && i != match
                         && output_hregno == input_hregno)
-                 error ("invalid hard register usage between earlyclobber "
-                        "operand and input operand");
+                 {
+                   error ("invalid hard register usage between "
+                          "earlyclobber operand and input operand");
+                   error_seen = true;
+                 }
              }
        }
 
@@ -3307,7 +3318,10 @@ expand_asm_stmt (gasm *stmt)
            op = validize_mem (op);
 
          if (! allows_reg && !MEM_P (op))
-           error ("output number %d not directly addressable", i);
+           {
+             error ("output number %d not directly addressable", i);
+             error_seen = true;
+           }
          if ((! allows_mem && MEM_P (op) && GET_MODE (op) != BLKmode)
              || GET_CODE (op) == CONCAT)
            {
@@ -3347,6 +3361,19 @@ expand_asm_stmt (gasm *stmt)
        inout_opnum.safe_push (i);
     }
 
+  const char *str = gimple_asm_string (stmt);
+  if (error_seen)
+    {
+      ninputs = 0;
+      noutputs = 0;
+      inout_opnum.truncate (0);
+      output_rvec.truncate (0);
+      clobber_rvec.truncate (0);
+      constraints.truncate (0);
+      CLEAR_HARD_REG_SET (clobbered_regs);
+      str = "";
+    }
+
   auto_vec<rtx, MAX_RECOG_OPERANDS> input_rvec;
   auto_vec<machine_mode, MAX_RECOG_OPERANDS> input_mode;
 
@@ -3405,7 +3432,7 @@ expand_asm_stmt (gasm *stmt)
     }
 
   /* For in-out operands, copy output rtx to input rtx.  */
-  unsigned ninout = inout_opnum.length();
+  unsigned ninout = inout_opnum.length ();
   for (i = 0; i < ninout; i++)
     {
       int j = inout_opnum[i];
@@ -3459,7 +3486,7 @@ expand_asm_stmt (gasm *stmt)
 
   rtx body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                    : GET_MODE (output_rvec[0])),
-                                  ggc_strdup (gimple_asm_string (stmt)),
+                                  ggc_strdup (str),
                                   "", 0, argvec, constraintvec,
                                   labelvec, locus);
   MEM_VOLATILE_P (body) = gimple_asm_volatile_p (stmt);
index dbb2370510c7eda3f03be31bc8464dde1d87e792..5a9331b36e6fc6b246a5c12e0edda053f3f58c0d 100644 (file)
@@ -7119,9 +7119,14 @@ cxx_mark_addressable (tree exp, bool array_ref_p)
            && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
            && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
          return true;
+       x = TREE_OPERAND (x, 0);
+       break;
+
+      case COMPONENT_REF:
+       if (bitfield_p (x))
+         error ("attempt to take address of bit-field");
        /* FALLTHRU */
       case ADDR_EXPR:
-      case COMPONENT_REF:
       case ARRAY_REF:
       case REALPART_EXPR:
       case IMAGPART_EXPR:
index 2606998152d776bc6cb30dcca033e3c5978feed6..41bae9c188f7d668a628b85262732f5aa9f040f1 100644 (file)
@@ -6323,12 +6323,14 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
       if (!allows_reg && allows_mem)
        mark_addressable (TREE_VALUE (link));
 
+      tree orig = TREE_VALUE (link);
       tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
                            is_inout ? is_gimple_min_lval : is_gimple_lvalue,
                            fb_lvalue | fb_mayfail);
       if (tret == GS_ERROR)
        {
-         error ("invalid lvalue in %<asm%> output %d", i);
+         if (orig != error_mark_node)
+           error ("invalid lvalue in %<asm%> output %d", i);
          ret = tret;
        }
 
@@ -6523,8 +6525,9 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
          mark_addressable (TREE_VALUE (link));
          if (tret == GS_ERROR)
            {
-             error_at (EXPR_LOC_OR_LOC (TREE_VALUE (link), input_location),
-                       "memory input %d is not directly addressable", i);
+             if (inputv != error_mark_node)
+               error_at (EXPR_LOC_OR_LOC (TREE_VALUE (link), input_location),
+                         "memory input %d is not directly addressable", i);
              ret = tret;
            }
        }
diff --git a/gcc/testsuite/c-c++-common/pr100785.c b/gcc/testsuite/c-c++-common/pr100785.c
new file mode 100644 (file)
index 0000000..37ff0aa
--- /dev/null
@@ -0,0 +1,21 @@
+/* PR inline-asm/100785 */
+
+struct S { int a : 1; };
+
+void
+foo (struct S *x)
+{
+  __asm__ ("" : "+m" (x->a));  /* { dg-error "address of bit-field" } */
+}
+
+void
+bar (struct S *x)
+{
+  __asm__ ("" : "=m" (x->a));  /* { dg-error "address of bit-field" } */
+}
+
+void
+baz (struct S *x)
+{
+  __asm__ ("" : : "m" (x->a)); /* { dg-error "address of bit-field" } */
+}
index 11ee401e0307400f7489574ddf0f287d9e4eedb7..4cd7c59011ef8135f9dfec072b425f9e95ef8ea2 100644 (file)
@@ -15,7 +15,7 @@ f2 (void *x)
 {
   __asm volatile ("" : "=r" (*x));     /* { dg-warning "dereferencing" "deref" } */
 }                                      /* { dg-error "invalid use of void expression" "void expr" { target *-*-* } .-1 } */
-                                       /* { dg-error "invalid lvalue in 'asm' output 0" "invalid lvalue" { target *-*-* } .-2 } */
+
 void
 f3 (void *x)
 {
@@ -39,7 +39,7 @@ f6 (void *x)
 {
   __asm volatile ("" : "=g" (*x));     /* { dg-warning "dereferencing" "deref" } */
 }                                      /* { dg-error "invalid use of void expression" "void expr" { target *-*-* } .-1 } */
-                                       /* { dg-error "invalid lvalue in 'asm' output 0" "invalid lvalue" { target *-*-* } .-2 } */
+
 void
 f7 (struct S *x)
 {
index 2d2a00c43b70456948843b8a2caca670d3739e3f..e22600a2476356548e74b8510f94c5e96e4a47c3 100644 (file)
@@ -15,7 +15,7 @@ f2 (void *x)
 {
   __asm ("" : "=r" (*x));      /* { dg-warning "dereferencing" "deref" } */
 }                              /* { dg-error "invalid use of void expression" "void expr" { target *-*-* } .-1 } */
-                               /* { dg-error "invalid lvalue in 'asm' output 0" "invalid lvalue" { target *-*-* } .-2 } */
+
 void
 f3 (void *x)
 {
@@ -39,7 +39,7 @@ f6 (void *x)
 {
   __asm ("" : "=g" (*x));      /* { dg-warning "dereferencing" "deref" } */
 }                              /* { dg-error "invalid use of void expression" "void expr" { target *-*-* } .-1 } */
-                               /* { dg-error "invalid lvalue in 'asm' output 0" "invalid lvalue" { target *-*-* } .-2 } */
+
 void
 f7 (struct S *x)
 {