aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-06-21 13:30:42 +0200
committerJakub Jelinek <jakub@redhat.com>2021-06-21 13:32:36 +0200
commit644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa (patch)
treed49b4fd8f9aa4d3b3ba153fd9d64d17b90c988f2
parent62a3799f34939740c744328849910204e5cf48d5 (diff)
downloadgcc-644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa.zip
gcc-644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa.tar.gz
gcc-644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa.tar.bz2
inline-asm: Fix ICE with bitfields in "m" operands [PR100785]
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.
-rw-r--r--gcc/c/c-typeck.c11
-rw-r--r--gcc/cfgexpand.c43
-rw-r--r--gcc/cp/typeck.c7
-rw-r--r--gcc/gimplify.c9
-rw-r--r--gcc/testsuite/c-c++-common/pr100785.c21
-rw-r--r--gcc/testsuite/gcc.dg/pr48552-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/pr48552-2.c4
7 files changed, 82 insertions, 17 deletions
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 845d50f..77de881 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -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:
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 39e5b04..6394cfd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -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);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index dbb2370..5a9331b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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:
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 2606998..41bae9c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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
index 0000000..37ff0aa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr100785.c
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr48552-1.c b/gcc/testsuite/gcc.dg/pr48552-1.c
index 11ee401..4cd7c59 100644
--- a/gcc/testsuite/gcc.dg/pr48552-1.c
+++ b/gcc/testsuite/gcc.dg/pr48552-1.c
@@ -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)
{
diff --git a/gcc/testsuite/gcc.dg/pr48552-2.c b/gcc/testsuite/gcc.dg/pr48552-2.c
index 2d2a00c..e22600a 100644
--- a/gcc/testsuite/gcc.dg/pr48552-2.c
+++ b/gcc/testsuite/gcc.dg/pr48552-2.c
@@ -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)
{