aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2024-01-24 04:27:13 -0800
committerAndi Kleen <ak@linux.intel.com>2024-06-11 09:52:28 -0700
commit53ac88cedf9348b0139fa92c3257b877694f6194 (patch)
tree5525ad215ef852168853d3f5ffa76a710940c237 /gcc/cp
parent6ef8c905e0064c4dfb7ca302355fc20cb96b147b (diff)
downloadgcc-53ac88cedf9348b0139fa92c3257b877694f6194.zip
gcc-53ac88cedf9348b0139fa92c3257b877694f6194.tar.gz
gcc-53ac88cedf9348b0139fa92c3257b877694f6194.tar.bz2
C++: Support constexpr strings for asm statements
Some programing styles use a lot of inline assembler, and it is common to use very complex preprocessor macros to generate the assembler strings for the asm statements. In C++ there would be a typesafe alternative using templates and constexpr to generate the assembler strings, but unfortunately the asm statement requires plain string literals, so this doesn't work. This patch modifies the C++ parser to accept strings generated by constexpr instead of just plain strings. This requires new syntax because e.g. asm("..." : "r" (expr)) would be ambigious with a function call. I chose () to make it unique. For example now you can write constexpr const char *genasm() { return "insn"; } constexpr const char *genconstraint() { return "r"; } asm(genasm() :: (genconstraint()) (input)); The constexpr strings are allowed for the asm template, the constraints and the clobbers (every time current asm accepts a string) This version allows the same constexprs as C++26 static_assert, following Jakub's suggestion. The drawback of this scheme is that the constexpr doesn't have full control over the input/output/clobber lists, but that can be usually handled with a switch statement. One could imagine more flexible ways to handle that, for example supporting constexpr vectors for the clobber list, or similar. But even without that it is already useful. Bootstrapped and full test on x86_64-linux. gcc/c-family/ChangeLog: * c-cppbuiltin.cc (c_cpp_builtins): Define __GXX_CONSTEXPR_ASM__ gcc/cp/ChangeLog: * parser.cc (cp_parser_asm_string_expression): New function to handle constexpr strings for asm. (cp_parser_asm_definition): Use cp_parser_asm_string_expression. (cp_parser_yield_expression): Dito. (cp_parser_asm_specification_opt): Dito. (cp_parser_asm_operand_list): Dito. (cp_parser_asm_clobber_list): Dito. gcc/ChangeLog: * doc/extend.texi: Document constexpr asm. gcc/testsuite/ChangeLog: * g++.dg/ext/asm11.C: Adjust to new error message. * g++.dg/ext/asm9.C: Dito. * g++.dg/parse/asm1.C: Dito. * g++.dg/parse/asm2.C: Dito. * g++.dg/parse/asm3.C: Dito. * g++.dg/cpp1z/constexpr-asm-1.C: New test. * g++.dg/cpp1z/constexpr-asm-2.C: New test. * g++.dg/cpp1z/constexpr-asm-3.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/parser.cc85
1 files changed, 62 insertions, 23 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9f43a77..6cd7274 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -22833,6 +22833,52 @@ cp_parser_using_directive (cp_parser* parser)
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
}
+/* Parse a string literal or constant expression yielding a string.
+ The constant expression uses extra parens to avoid ambiguity with "x" (expr).
+
+ asm-string-expr:
+ string-literal
+ ( constant-expr ) */
+
+static tree
+cp_parser_asm_string_expression (cp_parser *parser)
+{
+ cp_token *tok = cp_lexer_peek_token (parser->lexer);
+
+ if (tok->type == CPP_OPEN_PAREN)
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ tree string = cp_parser_constant_expression (parser);
+ if (string != error_mark_node)
+ string = cxx_constant_value (string, tf_error);
+ if (TREE_CODE (string) == NOP_EXPR)
+ string = TREE_OPERAND (string, 0);
+ if (TREE_CODE (string) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (string, 0)) == STRING_CST)
+ string = TREE_OPERAND (string, 0);
+ if (TREE_CODE (string) == VIEW_CONVERT_EXPR)
+ string = TREE_OPERAND (string, 0);
+ cexpr_str cstr (string);
+ if (!cstr.type_check (tok->location))
+ return error_mark_node;
+ const char *msg;
+ int len;
+ if (!cstr.extract (tok->location, msg, len))
+ return error_mark_node;
+ parens.require_close (parser);
+ string = build_string (len, msg);
+ return string;
+ }
+ else if (!cp_parser_is_string_literal (tok))
+ {
+ error_at (tok->location,
+ "expected string-literal or constexpr in brackets");
+ return error_mark_node;
+ }
+ return cp_parser_string_literal (parser, false, false);
+}
+
/* Parse an asm-definition.
asm-qualifier:
@@ -22845,19 +22891,19 @@ cp_parser_using_directive (cp_parser* parser)
asm-qualifier-list asm-qualifier
asm-definition:
- asm ( string-literal ) ;
+ asm ( constant-expr ) ;
GNU Extension:
asm-definition:
- asm asm-qualifier-list [opt] ( string-literal ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr ) ;
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt] ) ;
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt]
: asm-operand-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr : asm-operand-list [opt]
: asm-operand-list [opt]
: asm-clobber-list [opt] ) ;
- asm asm-qualifier-list [opt] ( string-literal : : asm-operand-list [opt]
+ asm asm-qualifier-list [opt] ( asm-string-expr : : asm-operand-list [opt]
: asm-clobber-list [opt]
: asm-goto-list ) ;
@@ -22976,8 +23022,7 @@ cp_parser_asm_definition (cp_parser* parser)
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return;
/* Look for the string. */
- tree string = cp_parser_string_literal (parser, /*translate=*/false,
- /*wide_ok=*/false);
+ tree string = cp_parser_asm_string_expression (parser);
if (string == error_mark_node)
{
cp_parser_skip_to_closing_parenthesis (parser, true, false,
@@ -29647,7 +29692,7 @@ cp_parser_yield_expression (cp_parser* parser)
/* Parse an (optional) asm-specification.
asm-specification:
- asm ( string-literal )
+ asm ( asm-string-expr )
If the asm-specification is present, returns a STRING_CST
corresponding to the string-literal. Otherwise, returns
@@ -29670,9 +29715,7 @@ cp_parser_asm_specification_opt (cp_parser* parser)
parens.require_open (parser);
/* Look for the string-literal. */
- tree asm_specification = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ tree asm_specification = cp_parser_asm_string_expression (parser);
/* Look for the `)'. */
parens.require_close (parser);
@@ -29687,8 +29730,8 @@ cp_parser_asm_specification_opt (cp_parser* parser)
asm-operand-list , asm-operand
asm-operand:
- string-literal ( expression )
- [ string-literal ] string-literal ( expression )
+ asm-string-expr ( expression )
+ [ asm-string-expr ] asm-string-expr ( expression )
Returns a TREE_LIST representing the operands. The TREE_VALUE of
each node is the expression. The TREE_PURPOSE is itself a
@@ -29721,10 +29764,8 @@ cp_parser_asm_operand_list (cp_parser* parser)
}
else
name = NULL_TREE;
- /* Look for the string-literal. */
- tree string_literal = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ /* Look for the string. */
+ tree string_literal = cp_parser_asm_string_expression (parser);
/* Look for the `('. */
matching_parens parens;
@@ -29757,8 +29798,8 @@ cp_parser_asm_operand_list (cp_parser* parser)
/* Parse an asm-clobber-list.
asm-clobber-list:
- string-literal
- asm-clobber-list , string-literal
+ const-expression
+ asm-clobber-list , const-expression
Returns a TREE_LIST, indicating the clobbers in the order that they
appeared. The TREE_VALUE of each node is a STRING_CST. */
@@ -29771,9 +29812,7 @@ cp_parser_asm_clobber_list (cp_parser* parser)
while (true)
{
/* Look for the string literal. */
- tree string_literal = cp_parser_string_literal (parser,
- /*translate=*/false,
- /*wide_ok=*/false);
+ tree string_literal = cp_parser_asm_string_expression (parser);
/* Add it to the list. */
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
/* If the next token is not a `,', then the list is