On Thu, Nov 21, 2024 at 09:32:51PM +0000, Joseph Myers wrote: > On Sat, 2 Nov 2024, Jakub Jelinek wrote: > > > +Extended @code{asm} statements outside of functions may not use any > > +qualifiers, may not specify clobbers, may not use @code{%}, @code{+} or > > +@code{&} modifiers in constraints and can only use constraints which don%'t > > +allow using any register. > > Just ' in Texinfo, not %'. > > > @@ -3071,7 +3072,62 @@ c_parser_declaration_or_fndef (c_parser > > static void > > c_parser_asm_definition (c_parser *parser) > > { > > - tree asm_str = c_parser_simple_asm_expr (parser); > > + location_t asm_loc = c_parser_peek_token (parser)->location; > > The syntax comment above this function needs updating. > > The C front-end changes are OK with that fix.
Thanks. Here is the adjusted patch. 2024-11-22 Jakub Jelinek <ja...@redhat.com> PR c/41045 gcc/ * output.h (insn_noperands): Declare. * final.cc (insn_noperands): No longer static. * varasm.cc (assemble_asm): Handle ASM_EXPR. * lto-streamer-out.cc (lto_output_toplevel_asms): Add sorry_at for non-STRING_CST toplevel asm for now. * doc/extend.texi (Basic @code{asm}, Extended @code{asm}): Document that extended asm is now allowed outside of functions with certain restrictions. gcc/c/ * c-parser.cc (c_parser_asm_string_literal): Add forward declaration. (c_parser_asm_definition): Parse also extended asm without clobbers/labels. * c-typeck.cc (build_asm_expr): Allow extended asm outside of functions and check extra restrictions. gcc/cp/ * cp-tree.h (finish_asm_stmt): Add TOPLEV_P argument. * parser.cc (cp_parser_asm_definition): Parse also extended asm without clobbers/labels outside of functions. * semantics.cc (finish_asm_stmt): Add TOPLEV_P argument, if set, check extra restrictions for extended asm outside of functions. * pt.cc (tsubst_stmt): Adjust finish_asm_stmt caller. gcc/testsuite/ * c-c++-common/toplevel-asm-1.c: New test. * c-c++-common/toplevel-asm-2.c: New test. * c-c++-common/toplevel-asm-3.c: New test. --- gcc/output.h.jj 2024-10-02 13:30:11.006426823 +0200 +++ gcc/output.h 2024-11-01 14:59:28.563541848 +0100 @@ -338,6 +338,9 @@ extern rtx_insn *current_output_insn; The precise value is the insn being output, to pass to error_for_asm. */ extern const rtx_insn *this_is_asm_operands; +/* Number of operands of this insn, for an `asm' with operands. */ +extern unsigned int insn_noperands; + /* Carry information from ASM_DECLARE_OBJECT_NAME to ASM_FINISH_DECLARE_OBJECT. */ extern int size_directive_output; --- gcc/final.cc.jj 2024-10-24 18:53:38.780079517 +0200 +++ gcc/final.cc 2024-11-01 14:59:28.980535887 +0100 @@ -150,7 +150,7 @@ extern const int length_unit_log; /* Thi const rtx_insn *this_is_asm_operands; /* Number of operands of this insn, for an `asm' with operands. */ -static unsigned int insn_noperands; +unsigned int insn_noperands; /* Compare optimization flag. */ --- gcc/varasm.cc.jj 2024-10-29 13:51:43.247898084 +0100 +++ gcc/varasm.cc 2024-11-01 16:46:23.998237127 +0100 @@ -62,6 +62,8 @@ along with GCC; see the file COPYING3. #include "toplev.h" #include "opts.h" #include "asan.h" +#include "recog.h" +#include "gimple-expr.h" /* The (assembler) name of the first globally-visible object output. */ extern GTY(()) const char *first_global_object_name; @@ -1667,16 +1669,167 @@ make_decl_rtl_for_debug (tree decl) for an `asm' keyword used between functions. */ void -assemble_asm (tree string) +assemble_asm (tree asm_str) { const char *p; - app_enable (); - if (TREE_CODE (string) == ADDR_EXPR) - string = TREE_OPERAND (string, 0); + if (TREE_CODE (asm_str) != ASM_EXPR) + { + app_enable (); + if (TREE_CODE (asm_str) == ADDR_EXPR) + asm_str = TREE_OPERAND (asm_str, 0); + + p = TREE_STRING_POINTER (asm_str); + fprintf (asm_out_file, "%s%s\n", p[0] == '\t' ? "" : "\t", p); + } + else + { + location_t save_loc = input_location; + int save_reload_completed = reload_completed; + int save_cse_not_expected = cse_not_expected; + input_location = EXPR_LOCATION (asm_str); + int noutputs = list_length (ASM_OUTPUTS (asm_str)); + int ninputs = list_length (ASM_INPUTS (asm_str)); + const char **constraints = NULL; + int i; + tree tail; + bool allows_mem, allows_reg, is_inout; + rtx *ops = NULL; + if (noutputs + ninputs > MAX_RECOG_OPERANDS) + { + error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS); + goto done; + } + constraints = XALLOCAVEC (const char *, noutputs + ninputs); + ops = XALLOCAVEC (rtx, noutputs + ninputs); + memset (&recog_data, 0, sizeof (recog_data)); + recog_data.n_operands = ninputs + noutputs; + recog_data.is_asm = true; + reload_completed = 0; + cse_not_expected = 1; + for (i = 0, tail = ASM_OUTPUTS (asm_str); tail; + ++i, tail = TREE_CHAIN (tail)) + { + tree output = TREE_VALUE (tail); + if (output == error_mark_node) + goto done; + constraints[i] + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + if (!parse_output_constraint (&constraints[i], i, ninputs, noutputs, + &allows_mem, &allows_reg, &is_inout)) + goto done; + if (is_inout) + { + error ("%qc in output operand outside of a function", '+'); + goto done; + } + if (strchr (constraints[i], '&')) + { + error ("%qc in output operand outside of a function", '&'); + goto done; + } + if (strchr (constraints[i], '%')) + { + error ("%qc in output operand outside of a function", '%'); + goto done; + } + output_addressed_constants (output, 0); + if (!is_gimple_addressable (output)) + { + error ("output number %d not directly addressable", i); + goto done; + } + ops[i] = expand_expr (build_fold_addr_expr (output), NULL_RTX, + VOIDmode, EXPAND_INITIALIZER); + ops[i] = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (output)), ops[i]); + + recog_data.operand[i] = ops[i]; + recog_data.operand_loc[i] = &ops[i]; + recog_data.constraints[i] = constraints[i]; + recog_data.operand_mode[i] = TYPE_MODE (TREE_TYPE (output)); + } + for (i = 0, tail = ASM_INPUTS (asm_str); tail; + ++i, tail = TREE_CHAIN (tail)) + { + tree input = TREE_VALUE (tail); + if (input == error_mark_node) + goto done; + constraints[i + noutputs] + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); + if (!parse_input_constraint (&constraints[i + noutputs], i, + ninputs, noutputs, 0, constraints, + &allows_mem, &allows_reg)) + goto done; + if (strchr (constraints[i], '%')) + { + error ("%qc in input operand outside of a function", '%'); + goto done; + } + const char *constraint = constraints[i + noutputs]; + size_t c_len = strlen (constraint); + for (size_t j = 0; j < c_len; + j += CONSTRAINT_LEN (constraint[j], constraint + j)) + if (constraint[j] >= '0' && constraint[j] <= '9') + { + error ("matching constraint outside of a function"); + goto done; + } + output_addressed_constants (input, 0); + if (allows_mem && is_gimple_addressable (input)) + { + ops[i + noutputs] + = expand_expr (build_fold_addr_expr (input), NULL_RTX, + VOIDmode, EXPAND_INITIALIZER); + ops[i + noutputs] = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (input)), + ops[i + noutputs]); + } + else + ops[i + noutputs] = expand_expr (input, NULL_RTX, VOIDmode, + EXPAND_INITIALIZER); + if (asm_operand_ok (ops[i + noutputs], constraint, NULL) <= 0) + { + if (!allows_mem) + warning (0, "%<asm%> operand %d probably does not " + "match constraints", i + noutputs); + } + recog_data.operand[i + noutputs] = ops[i + noutputs]; + recog_data.operand_loc[i + noutputs] = &ops[i + noutputs]; + recog_data.constraints[i + noutputs] = constraints[i + noutputs]; + recog_data.operand_mode[i + noutputs] + = TYPE_MODE (TREE_TYPE (input)); + } + if (recog_data.n_operands > 0) + { + const char *p = recog_data.constraints[0]; + recog_data.n_alternatives = 1; + while (*p) + recog_data.n_alternatives += (*p++ == ','); + } + for (i = 0; i < recog_data.n_operands; i++) + recog_data.operand_type[i] + = recog_data.constraints[i][0] == '=' ? OP_OUT : OP_IN; + reload_completed = 1; + constrain_operands (1, ALL_ALTERNATIVES); + if (which_alternative < 0) + { + error ("impossible constraint in %<asm%>"); + goto done; + } + this_is_asm_operands = make_insn_raw (gen_nop ()); + insn_noperands = recog_data.n_operands; + if (TREE_STRING_POINTER (ASM_STRING (asm_str))[0]) + { + app_enable (); + output_asm_insn (TREE_STRING_POINTER (ASM_STRING (asm_str)), ops); + } + insn_noperands = 0; + this_is_asm_operands = NULL; - p = TREE_STRING_POINTER (string); - fprintf (asm_out_file, "%s%s\n", p[0] == '\t' ? "" : "\t", p); + done: + input_location = save_loc; + reload_completed = save_reload_completed; + cse_not_expected = save_cse_not_expected; + } } /* Write the address of the entity given by SYMBOL to SEC. */ --- gcc/lto-streamer-out.cc.jj 2024-10-25 10:00:29.489767556 +0200 +++ gcc/lto-streamer-out.cc 2024-11-01 17:35:28.700127715 +0100 @@ -2543,6 +2543,13 @@ lto_output_toplevel_asms (void) for (can = symtab->first_asm_symbol (); can; can = can->next) { + if (TREE_CODE (can->asm_str) != STRING_CST) + { + sorry_at (EXPR_LOCATION (can->asm_str), + "LTO streaming of toplevel extended %<asm%> " + "unimplemented"); + continue; + } streamer_write_string_cst (ob, ob->main_stream, can->asm_str); streamer_write_hwi (ob, can->order); } --- gcc/doc/extend.texi.jj 2024-11-01 11:49:46.722734014 +0100 +++ gcc/doc/extend.texi 2024-11-01 14:59:28.985535816 +0100 @@ -10839,8 +10839,8 @@ statements. A @dfn{basic @code{asm}} st operands (@pxref{Basic Asm}), while an @dfn{extended @code{asm}} statement (@pxref{Extended Asm}) includes one or more operands. The extended form is preferred for mixing C and assembly language -within a function, but to include assembly language at -top level you must use basic @code{asm}. +within a function and can be used at top level as well with certain +restrictions. You can also use the @code{asm} keyword to override the assembler name for a C symbol, or to place a C variable in a specific register. @@ -10878,6 +10878,8 @@ can be used for code compiled with @opti @item volatile The optional @code{volatile} qualifier has no effect. All basic @code{asm} blocks are implicitly volatile. +Basic @code{asm} statements outside of functions may not use any +qualifiers. @item inline If you use the @code{inline} qualifier, then for inlining purposes the size @@ -10922,25 +10924,19 @@ void function() @subsubheading Remarks Using extended @code{asm} (@pxref{Extended Asm}) typically produces smaller, safer, and more efficient code, and in most cases it is a -better solution than basic @code{asm}. However, there are two -situations where only basic @code{asm} can be used: +better solution than basic @code{asm}. However, functions declared +with the @code{naked} attribute require only basic @code{asm} +(@pxref{Function Attributes}). -@itemize @bullet -@item -Extended @code{asm} statements have to be inside a C -function, so to write inline assembly language at file scope (``top-level''), -outside of C functions, you must use basic @code{asm}. -You can use this technique to emit assembler directives, +Extended @code{asm} statements may be used both inside a C +function or at file scope (``top-level''), where +you can use this technique to emit assembler directives, define assembly language macros that can be invoked elsewhere in the file, or write entire functions in assembly language. -Basic @code{asm} statements outside of functions may not use any -qualifiers. - -@item -Functions declared -with the @code{naked} attribute also require basic @code{asm} -(@pxref{Function Attributes}). -@end itemize +Extended @code{asm} statements outside of functions may not use any +qualifiers, may not specify clobbers, may not use @code{%}, @code{+} or +@code{&} modifiers in constraints and can only use constraints which don't +allow using any register. Safely accessing C data and calling functions from basic @code{asm} is more complex than it may appear. To access C data, it is better to use extended --- gcc/c/c-parser.cc.jj 2024-10-31 21:17:06.861021154 +0100 +++ gcc/c/c-parser.cc 2024-11-22 10:38:04.201298498 +0100 @@ -1662,6 +1662,7 @@ static struct c_arg_info *c_parser_parms static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree, tree, bool); static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool); +static tree c_parser_asm_string_literal (c_parser *); static tree c_parser_simple_asm_expr (c_parser *); static tree c_parser_gnu_attributes (c_parser *); static struct c_expr c_parser_initializer (c_parser *, tree); @@ -3103,12 +3104,74 @@ c_parser_declaration_or_fndef (c_parser asm-definition: simple-asm-expr ; -*/ + asm ( toplevel-asm-argument ) ; + + toplevel-asm-argument: + asm-string-literal + asm-string-literal : asm-operands[opt] + asm-string-literal : asm-operands[opt] : asm-operands[opt] + + The :: token is considered equivalent to two consecutive : tokens. */ static void c_parser_asm_definition (c_parser *parser) { - tree asm_str = c_parser_simple_asm_expr (parser); + location_t asm_loc = c_parser_peek_token (parser)->location; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM)); + c_parser_consume_token (parser); + matching_parens parens; + tree asm_str = NULL_TREE; + tree outputs = NULL_TREE, inputs = NULL_TREE; + if (!parens.require_open (parser)) + goto done; + asm_str = c_parser_asm_string_literal (parser); + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + parens.require_close (parser); + goto done; + } + for (int section = 0; section < 2; ++section) + { + if (c_parser_next_token_is (parser, CPP_SCOPE)) + { + ++section; + if (section == 2) + { + c_parser_error (parser, "expected %<)%>"); + error_close_paren: + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + asm_str = NULL_TREE; + goto done; + } + c_parser_consume_token (parser); + } + else if (!c_parser_require (parser, CPP_COLON, + "expected %<:%> or %<)%>", + UNKNOWN_LOCATION, false)) + goto error_close_paren; + if (!c_parser_next_token_is (parser, CPP_COLON) + && !c_parser_next_token_is (parser, CPP_SCOPE) + && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + { + if (section) + inputs = c_parser_asm_operands (parser); + else + outputs = c_parser_asm_operands (parser); + } + if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + break; + } + + if (!parens.require_close (parser)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + asm_str = NULL_TREE; + } + + if (asm_str) + asm_str = build_asm_expr (asm_loc, asm_str, outputs, inputs, + NULL_TREE, NULL_TREE, false, false); +done: if (asm_str) symtab->finalize_toplevel_asm (asm_str); c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); --- gcc/c/c-typeck.cc.jj 2024-10-31 21:17:06.909020481 +0100 +++ gcc/c/c-typeck.cc 2024-11-01 14:59:29.021535301 +0100 @@ -12171,10 +12171,37 @@ build_asm_expr (location_t loc, tree str error_at (loc, "invalid use of void expression"); output = error_mark_node; } + if (allows_reg && current_function_decl == NULL_TREE) + { + error_at (loc, "invalid constraint outside of a function"); + output = error_mark_node; + } } else output = error_mark_node; + if (current_function_decl == NULL_TREE && output != error_mark_node) + { + if (TREE_SIDE_EFFECTS (output)) + { + error_at (loc, "side-effects in output operand outside " + "of a function"); + output = error_mark_node; + } + else + { + tree addr = build_unary_op (loc, ADDR_EXPR, output, false); + if (addr == error_mark_node) + output = error_mark_node; + else if (!initializer_constant_valid_p (addr, TREE_TYPE (addr))) + { + error_at (loc, "output operand outside of a function is not " + "constant"); + output = error_mark_node; + } + } + } + TREE_VALUE (tail) = output; } @@ -12214,10 +12241,37 @@ build_asm_expr (location_t loc, tree str input = error_mark_node; } } + if (allows_reg && current_function_decl == NULL_TREE) + { + error_at (loc, "invalid constraint outside of a function"); + input = error_mark_node; + } } else input = error_mark_node; + if (current_function_decl == NULL_TREE && input != error_mark_node) + { + if (TREE_SIDE_EFFECTS (input)) + { + error_at (loc, "side-effects in input operand outside " + "of a function"); + input = error_mark_node; + } + else + { + tree tem = input; + if (allows_mem && lvalue_p (input)) + tem = build_unary_op (loc, ADDR_EXPR, input, false); + if (!initializer_constant_valid_p (tem, TREE_TYPE (tem))) + { + error_at (loc, "input operand outside of a function is not " + "constant"); + input = error_mark_node; + } + } + } + TREE_VALUE (tail) = input; } --- gcc/cp/cp-tree.h.jj 2024-10-25 10:00:29.409768701 +0200 +++ gcc/cp/cp-tree.h 2024-11-01 14:59:29.023535272 +0100 @@ -7854,7 +7854,7 @@ extern tree begin_compound_stmt (unsig extern void finish_compound_stmt (tree); extern tree finish_asm_stmt (location_t, int, tree, tree, - tree, tree, tree, bool); + tree, tree, tree, bool, bool); extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern cp_expr finish_parenthesized_expr (cp_expr); --- gcc/cp/parser.cc.jj 2024-10-25 10:00:29.427768443 +0200 +++ gcc/cp/parser.cc 2024-11-01 14:59:29.036535086 +0100 @@ -23112,7 +23112,6 @@ cp_parser_asm_definition (cp_parser* par too. Doing that means that we have to treat the `::' operator as two `:' tokens. */ if (cp_parser_allow_gnu_extensions_p (parser) - && parser->in_function_body && (cp_lexer_next_token_is (parser->lexer, CPP_COLON) || cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))) { @@ -23166,13 +23165,15 @@ cp_parser_asm_definition (cp_parser* par invalid_inputs_p = true; } } - else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + else if (parser->in_function_body + && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) /* The clobbers are coming next. */ clobbers_p = true; /* Look for clobbers. */ if (clobbers_p - || cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + || (parser->in_function_body + && cp_lexer_next_token_is (parser->lexer, CPP_COLON))) { clobbers_p = true; /* Consume the `:' or `::'. */ @@ -23218,7 +23219,8 @@ cp_parser_asm_definition (cp_parser* par if (parser->in_function_body) { asm_stmt = finish_asm_stmt (asm_loc, volatile_p, string, outputs, - inputs, clobbers, labels, inline_p); + inputs, clobbers, labels, inline_p, + false); /* If the extended syntax was not used, mark the ASM_EXPR. */ if (!extended_p) { @@ -23229,8 +23231,11 @@ cp_parser_asm_definition (cp_parser* par ASM_BASIC_P (temp) = 1; } } - else + else if (!extended_p) symtab->finalize_toplevel_asm (string); + else + finish_asm_stmt (asm_loc, false, string, outputs, inputs, + NULL_TREE, NULL_TREE, false, true); } if (std_attrs && any_nonignored_attribute_p (std_attrs)) --- gcc/cp/semantics.cc.jj 2024-10-29 13:51:33.257037334 +0100 +++ gcc/cp/semantics.cc 2024-11-01 14:59:29.039535043 +0100 @@ -2137,12 +2137,13 @@ finish_compound_stmt (tree stmt) /* Finish an asm-statement, whose components are a STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, some CLOBBERS and some LABELS. Also note whether the asm-statement should be - considered volatile, and whether it is asm inline. */ + considered volatile, and whether it is asm inline. TOPLEV_P + is true if finishing namespace scope extended asm. */ tree finish_asm_stmt (location_t loc, int volatile_p, tree string, tree output_operands, tree input_operands, tree clobbers, - tree labels, bool inline_p) + tree labels, bool inline_p, bool toplev_p) { tree r; tree t; @@ -2216,10 +2217,45 @@ finish_asm_stmt (location_t loc, int vol mark it addressable. */ if (!allows_reg && !cxx_mark_addressable (*op)) operand = error_mark_node; + if (allows_reg && toplev_p) + { + error_at (loc, "invalid constraint outside of a function"); + operand = error_mark_node; + } } else operand = error_mark_node; + if (toplev_p && operand != error_mark_node) + { + if (TREE_SIDE_EFFECTS (operand)) + { + error_at (loc, "side-effects in output operand outside " + "of a function"); + operand = error_mark_node; + } + else + { + tree addr + = cp_build_addr_expr (operand, tf_warning_or_error); + if (addr == error_mark_node) + operand = error_mark_node; + else + { + addr = maybe_constant_value (addr); + if (!initializer_constant_valid_p (addr, + TREE_TYPE (addr))) + { + error_at (loc, "output operand outside of a " + "function is not constant"); + operand = error_mark_node; + } + else + operand = build_fold_indirect_ref (addr); + } + } + } + TREE_VALUE (t) = operand; } @@ -2284,10 +2320,55 @@ finish_asm_stmt (location_t loc, int vol if (TREE_CONSTANT (constop)) operand = constop; } + if (allows_reg && toplev_p) + { + error_at (loc, "invalid constraint outside of a function"); + operand = error_mark_node; + } } else operand = error_mark_node; + if (toplev_p && operand != error_mark_node) + { + if (TREE_SIDE_EFFECTS (operand)) + { + error_at (loc, "side-effects in input operand outside " + "of a function"); + operand = error_mark_node; + } + else if (allows_mem && lvalue_or_else (operand, lv_asm, tf_none)) + { + tree addr = cp_build_addr_expr (operand, tf_warning_or_error); + if (addr == error_mark_node) + operand = error_mark_node; + else + { + addr = maybe_constant_value (addr); + if (!initializer_constant_valid_p (addr, + TREE_TYPE (addr))) + { + error_at (loc, "input operand outside of a " + "function is not constant"); + operand = error_mark_node; + } + else + operand = build_fold_indirect_ref (addr); + } + } + else + { + operand = maybe_constant_value (operand); + if (!initializer_constant_valid_p (operand, + TREE_TYPE (operand))) + { + error_at (loc, "input operand outside of a " + "function is not constant"); + operand = error_mark_node; + } + } + } + TREE_VALUE (t) = operand; } } @@ -2297,6 +2378,11 @@ finish_asm_stmt (location_t loc, int vol clobbers, labels); ASM_VOLATILE_P (r) = volatile_p || noutputs == 0; ASM_INLINE_P (r) = inline_p; + if (toplev_p) + { + symtab->finalize_toplevel_asm (r); + return r; + } r = maybe_cleanup_point_expr_void (r); return add_stmt (r); } --- gcc/cp/pt.cc.jj 2024-11-01 11:57:23.900128987 +0100 +++ gcc/cp/pt.cc 2024-11-01 14:59:29.047534929 +0100 @@ -18982,7 +18982,7 @@ tsubst_stmt (tree t, tree args, tsubst_f complain, in_decl); tmp = finish_asm_stmt (EXPR_LOCATION (t), ASM_VOLATILE_P (t), string, outputs, inputs, clobbers, labels, - ASM_INLINE_P (t)); + ASM_INLINE_P (t), false); tree asm_expr = tmp; if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR) asm_expr = TREE_OPERAND (asm_expr, 0); --- gcc/testsuite/c-c++-common/toplevel-asm-1.c.jj 2024-11-01 15:09:46.209708353 +0100 +++ gcc/testsuite/c-c++-common/toplevel-asm-1.c 2024-11-01 19:25:47.512567789 +0100 @@ -0,0 +1,25 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pie" { target pie } } */ + +struct S { char a; long long b; int c; }; +enum E { E0, E1 = sizeof (struct S) + 15 }; +int v[42]; +void foo (void) {} + +asm ("# %0 %1 %2 %c3 %c4 %5 %% %=" + :: "i" (sizeof (struct S)), + "i" (__builtin_offsetof (struct S, c)), + "i" (E1), + "s" (foo), + "i" (v), +/* Not all targets can satisfy "m" even in non-pic code. */ +#if !defined(__i386__) && !defined(__x86_64__) + "s" (v)); +#else + "m" (v)); +asm ("# %0 %1" + : "=m" (v[16]) + : "m" (v[41])); +#endif --- gcc/testsuite/c-c++-common/toplevel-asm-2.c.jj 2024-11-01 17:33:35.173750585 +0100 +++ gcc/testsuite/c-c++-common/toplevel-asm-2.c 2024-11-01 17:52:37.657418058 +0100 @@ -0,0 +1,21 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pie" { target pie } } */ + +int v[42], w[42], x; +void l1 (void); + +asm ("# %0" : "=m" (32)); /* { dg-error "lvalue required in 'asm' statement" } */ +asm ("# %0" : "=m" (v) : "0" (v)); /* { dg-warning "matching constraint does not allow a register" } */ +asm ("# %0" : : "m" (v), "0" (v)); /* { dg-error "matching constraint references invalid operand number" } */ +asm ("# %0" :: "i" (0) : "cc"); /* { dg-error "expected '\\\)' before ':' token" } */ +asm ("# %0" : : "i" (0) :: l1); /* { dg-error "expected '\\\)' before '::?' token" } */ +asm ("# %0" : "=r" (x)); /* { dg-error "invalid constraint outside of a function" } */ +asm ("# %0" : "=m" (x++)); /* { dg-error "lvalue required in 'asm' statement" } */ +asm ("# %0" : "=m" (v[x])); /* { dg-error "output operand outside of a function is not constant" } */ +asm ("# %0" :: "r" (x)); /* { dg-error "invalid constraint outside of a function" } */ +asm ("# %0" : : "m" (x++)); /* { dg-error "side-effects in input operand outside of a function" } */ +asm ("# %0" : : "m" (v[x])); /* { dg-error "input operand outside of a function is not constant" } */ +asm ("# %0" : : "i" (v[x])); /* { dg-error "input operand outside of a function is not constant" } */ +asm ("# %0" : : "i" (x++)); /* { dg-error "side-effects in input operand outside of a function" } */ --- gcc/testsuite/c-c++-common/toplevel-asm-3.c.jj 2024-11-01 17:45:33.482482325 +0100 +++ gcc/testsuite/c-c++-common/toplevel-asm-3.c 2024-11-01 17:53:46.399435004 +0100 @@ -0,0 +1,11 @@ +/* PR c/41045 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-fno-pie" { target pie } } */ + +int v[42], w[42], x; + +asm ("# %0" : "+m" (v)); /* { dg-error "'\\\+' in output operand outside of a function" } */ +asm ("# %0" : "=&m" (v)); /* { dg-error "'&' in output operand outside of a function" } */ +asm ("# %0, %1" : "=%m" (v), "=m" (w)); /* { dg-error "'%' in output operand outside of a function" } */ +asm ("# %0, %1" : : "%m" (v), "m" (w)); /* { dg-error "'%' in input operand outside of a function" } */ Jakub