Hi! While in C, x = 10 or ++x or --x aren't lvalues and so we reject such expressions in inline asm output operands (and inputs that only allow memory, not registers), in C++ they apparently are lvalues; for output operands we ICE in the gimplifier on this, because in the generic code MODIFY_EXPR or PREINCREMENT_EXPR or PREDECREMENT_EXPR aren't considered to be lvalues, and for "m" inputs we just reject them, but when those expressions are allowed on lhs of a store, they should be IMHO allowed as "m" inputs too.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-03-20 Jakub Jelinek <ja...@redhat.com> PR c++/84961 * semantics.c (finish_asm_stmt): Replace MODIFY_EXPR, PREINCREMENT_EXPR and PREDECREMENT_EXPR in output and "m" constrained input operands with COMPOUND_EXPR. Call cxx_mark_addressable on the rightmost COMPOUND_EXPR operand. * c-c++-common/pr43690.c: Don't expect errors on "m" (--x) and "m" (++x) in C++. * g++.dg/torture/pr84961-1.C: New test. * g++.dg/torture/pr84961-2.C: New test. --- gcc/cp/semantics.c.jj 2018-03-20 11:58:17.069356145 +0100 +++ gcc/cp/semantics.c 2018-03-20 21:56:43.745292245 +0100 @@ -1512,6 +1512,26 @@ finish_asm_stmt (int volatile_p, tree st && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand))))) cxx_readonly_error (operand, lv_asm); + tree *op = &operand; + while (TREE_CODE (*op) == COMPOUND_EXPR) + op = &TREE_OPERAND (*op, 1); + switch (TREE_CODE (*op)) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case MODIFY_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (*op, 0))) + *op = build2 (TREE_CODE (*op), TREE_TYPE (*op), + cp_stabilize_reference (TREE_OPERAND (*op, 0)), + TREE_OPERAND (*op, 1)); + *op = build2 (COMPOUND_EXPR, TREE_TYPE (*op), *op, + TREE_OPERAND (*op, 0)); + op = &TREE_OPERAND (*op, 1); + break; + default: + break; + } + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); oconstraints[i] = constraint; @@ -1520,7 +1540,7 @@ finish_asm_stmt (int volatile_p, tree st { /* If the operand is going to end up in memory, mark it addressable. */ - if (!allows_reg && !cxx_mark_addressable (operand)) + if (!allows_reg && !cxx_mark_addressable (*op)) operand = error_mark_node; } else @@ -1562,7 +1582,30 @@ finish_asm_stmt (int volatile_p, tree st /* Strip the nops as we allow this case. FIXME, this really should be rejected or made deprecated. */ STRIP_NOPS (operand); - if (!cxx_mark_addressable (operand)) + + tree *op = &operand; + while (TREE_CODE (*op) == COMPOUND_EXPR) + op = &TREE_OPERAND (*op, 1); + switch (TREE_CODE (*op)) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case MODIFY_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (*op, 0))) + *op + = build2 (TREE_CODE (*op), TREE_TYPE (*op), + cp_stabilize_reference (TREE_OPERAND (*op, + 0)), + TREE_OPERAND (*op, 1)); + *op = build2 (COMPOUND_EXPR, TREE_TYPE (*op), *op, + TREE_OPERAND (*op, 0)); + op = &TREE_OPERAND (*op, 1); + break; + default: + break; + } + + if (!cxx_mark_addressable (*op)) operand = error_mark_node; } else if (!allows_reg && !allows_mem) --- gcc/testsuite/c-c++-common/pr43690.c.jj 2010-11-09 13:58:21.000000000 +0100 +++ gcc/testsuite/c-c++-common/pr43690.c 2018-03-20 21:58:43.077317034 +0100 @@ -6,8 +6,8 @@ void foo (char *x) { asm ("" : : "m" (x++)); /* { dg-error "is not directly addressable" } */ - asm ("" : : "m" (++x)); /* { dg-error "is not directly addressable" } */ + asm ("" : : "m" (++x)); /* { dg-error "is not directly addressable" "" { target c } } */ asm ("" : : "m" (x--)); /* { dg-error "is not directly addressable" } */ - asm ("" : : "m" (--x)); /* { dg-error "is not directly addressable" } */ + asm ("" : : "m" (--x)); /* { dg-error "is not directly addressable" "" { target c } } */ asm ("" : : "m" (x + 1)); /* { dg-error "is not directly addressable" } */ } --- gcc/testsuite/g++.dg/torture/pr84961-1.C.jj 2018-03-20 21:51:17.231238830 +0100 +++ gcc/testsuite/g++.dg/torture/pr84961-1.C 2018-03-20 21:51:17.231238830 +0100 @@ -0,0 +1,24 @@ +// PR c++/84961 +// { dg-do compile } + +short a; +volatile int b; +int c, d; + +void +foo () +{ + asm volatile ("" : "=r" (b = a)); +} + +void +bar () +{ + asm volatile ("" : "=r" (++c, ++d, b = a)); +} + +void +baz () +{ + asm volatile ("" : "=r" (--b)); +} --- gcc/testsuite/g++.dg/torture/pr84961-2.C.jj 2018-03-20 21:51:17.231238830 +0100 +++ gcc/testsuite/g++.dg/torture/pr84961-2.C 2018-03-20 21:51:17.231238830 +0100 @@ -0,0 +1,24 @@ +// PR c++/84961 +// { dg-do compile } + +short a; +volatile int b; +int c, d; + +void +foo () +{ + asm volatile ("" : : "m" (b = a)); +} + +void +bar () +{ + asm volatile ("" : : "m" (++c, ++d, b = a)); +} + +void +baz () +{ + asm volatile ("" : : "m" (--b)); +} Jakub