From 529bc4103b78fa16cbd93d7947724472a4ffb31e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 7 Aug 2019 14:20:40 +0000 Subject: [PATCH] PR c++/91346 - Implement P1668R1, allow unevaluated asm in constexpr. * constexpr.c (cxx_eval_constant_expression): Handle ASM_EXPR. (potential_constant_expression_1) : Allow. * cp-tree.h (finish_asm_stmt): Adjust. * parser.c (cp_parser_asm_definition): Grab the locaion of "asm" and use it. Change an error to a pedwarn. Allow asm in C++2a, warn otherwise. * pt.c (tsubst_expr): Pass a location down to finish_asm_stmt. * semantics.c (finish_asm_stmt): New location_t parameter. Use it. * g++.dg/cpp2a/inline-asm1.C: New test. * g++.dg/cpp2a/inline-asm2.C: New test. * g++.dg/cpp1y/constexpr-neg1.C: Adjust dg-error. From-SVN: r274169 --- gcc/cp/ChangeLog | 12 ++++++++++++ gcc/cp/constexpr.c | 19 ++++++++++++++++++- gcc/cp/cp-tree.h | 4 ++-- gcc/cp/parser.c | 14 ++++++++------ gcc/cp/pt.c | 5 +++-- gcc/cp/semantics.c | 14 ++++++++------ gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C | 2 +- gcc/testsuite/g++.dg/cpp2a/inline-asm1.C | 13 +++++++++++++ gcc/testsuite/g++.dg/cpp2a/inline-asm2.C | 17 +++++++++++++++++ 10 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/inline-asm1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/inline-asm2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c1e977b6926..64714e0600e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2019-08-07 Marek Polacek + + PR c++/91346 - Implement P1668R1, allow unevaluated asm in constexpr. + * constexpr.c (cxx_eval_constant_expression): Handle ASM_EXPR. + (potential_constant_expression_1) : Allow. + * cp-tree.h (finish_asm_stmt): Adjust. + * parser.c (cp_parser_asm_definition): Grab the locaion of "asm" and + use it. Change an error to a pedwarn. Allow asm in C++2a, warn + otherwise. + * pt.c (tsubst_expr): Pass a location down to finish_asm_stmt. + * semantics.c (finish_asm_stmt): New location_t parameter. Use it. + 2019-08-07 Jakub Jelinek * parser.c (cp_parser_omp_clause_name): Parse use_device_addr clause. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 36a66337433..e86b0789b84 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5289,6 +5289,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = void_node; break; + case ASM_EXPR: + if (!ctx->quiet) + { + error_at (cp_expr_loc_or_input_loc (t), + "inline assembly is not a constant expression"); + inform (cp_expr_loc_or_input_loc (t), + "only unevaluated inline assembly is allowed in a " + "% function in C++2a"); + } + *non_constant_p = true; + return t; + default: if (STATEMENT_CODE_P (TREE_CODE (t))) { @@ -6469,13 +6481,18 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, /* GCC internal stuff. */ case VA_ARG_EXPR: case TRANSACTION_EXPR: - case ASM_EXPR: case AT_ENCODE_EXPR: fail: if (flags & tf_error) error_at (loc, "expression %qE is not a constant expression", t); return false; + case ASM_EXPR: + /* In C++2a, unevaluated inline assembly is permitted in constexpr + functions. If it's used in earlier standard modes, we pedwarn in + cp_parser_asm_definition. */ + return true; + case OBJ_TYPE_REF: if (cxx_dialect >= cxx2a) /* In C++2a virtual calls can be constexpr, don't give up yet. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d4e67cdfd96..72ee1d61e97 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7052,8 +7052,8 @@ enum { extern tree begin_compound_stmt (unsigned int); extern void finish_compound_stmt (tree); -extern tree finish_asm_stmt (int, tree, tree, tree, tree, - tree, bool); +extern tree finish_asm_stmt (location_t, int, tree, tree, + tree, tree, tree, bool); extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern cp_expr finish_parenthesized_expr (cp_expr); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4d07a6a3011..ccf89f0856f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19817,16 +19817,18 @@ cp_parser_asm_definition (cp_parser* parser) bool invalid_inputs_p = false; bool invalid_outputs_p = false; required_token missing = RT_NONE; + location_t asm_loc = cp_lexer_peek_token (parser->lexer)->location; /* Look for the `asm' keyword. */ cp_parser_require_keyword (parser, RID_ASM, RT_ASM); + /* In C++2a, unevaluated inline assembly is permitted in constexpr + functions. */ if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) - { - error ("% in % function"); - cp_function_chain->invalid_constexpr = true; - } + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && (cxx_dialect < cxx2a)) + pedwarn (asm_loc, 0, "% in % function only available " + "with %<-std=c++2a%> or %<-std=gnu++2a%>"); /* Handle the asm-qualifier-list. */ location_t volatile_loc = UNKNOWN_LOCATION; @@ -20032,7 +20034,7 @@ cp_parser_asm_definition (cp_parser* parser) /* Create the ASM_EXPR. */ if (parser->in_function_body) { - asm_stmt = finish_asm_stmt (volatile_p, string, outputs, + asm_stmt = finish_asm_stmt (asm_loc, volatile_p, string, outputs, inputs, clobbers, labels, inline_p); /* If the extended syntax was not used, mark the ASM_EXPR. */ if (!extended_p) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b1ad99d1481..b03968febb4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17396,8 +17396,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, complain, in_decl); tree labels = tsubst_copy_asm_operands (ASM_LABELS (t), args, complain, in_decl); - tmp = finish_asm_stmt (ASM_VOLATILE_P (t), string, outputs, inputs, - clobbers, labels, ASM_INLINE_P (t)); + tmp = finish_asm_stmt (EXPR_LOCATION (t), ASM_VOLATILE_P (t), string, + outputs, inputs, clobbers, labels, + ASM_INLINE_P (t)); tree asm_expr = tmp; if (TREE_CODE (asm_expr) == CLEANUP_POINT_EXPR) asm_expr = TREE_OPERAND (asm_expr, 0); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 77e7a6dced2..8fe632f2239 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1484,8 +1484,9 @@ finish_compound_stmt (tree stmt) considered volatile, and whether it is asm inline. */ tree -finish_asm_stmt (int volatile_p, tree string, tree output_operands, - tree input_operands, tree clobbers, tree labels, bool inline_p) +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 r; tree t; @@ -1532,7 +1533,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, effectively const. */ || (CLASS_TYPE_P (TREE_TYPE (operand)) && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand))))) - cxx_readonly_error (input_location, operand, lv_asm); + cxx_readonly_error (loc, operand, lv_asm); tree *op = &operand; while (TREE_CODE (*op) == COMPOUND_EXPR) @@ -1585,8 +1586,9 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, resolve the overloading. */ if (TREE_TYPE (operand) == unknown_type_node) { - error ("type of % operand %qE could not be determined", - TREE_VALUE (t)); + error_at (loc, + "type of % operand %qE could not be determined", + TREE_VALUE (t)); operand = error_mark_node; } @@ -1634,7 +1636,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, } } - r = build_stmt (input_location, ASM_EXPR, string, + r = build_stmt (loc, ASM_EXPR, string, output_operands, input_operands, clobbers, labels); ASM_VOLATILE_P (r) = volatile_p || noutputs == 0; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1d412b60e5d..f2e6afc0e8d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-08-07 Marek Polacek + + PR c++/91346 - Implement P1668R1, allow unevaluated asm in constexpr. + * g++.dg/cpp2a/inline-asm1.C: New test. + * g++.dg/cpp2a/inline-asm2.C: New test. + * g++.dg/cpp1y/constexpr-neg1.C: Adjust dg-error. + 2019-08-07 Janne Blomqvist PR fortran/53796 diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C index ae3dcc69cf0..d82dbada1bf 100644 --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C @@ -7,7 +7,7 @@ constexpr int f(int i) { thread_local int l = i; // { dg-error "thread_local" } goto foo; // { dg-error "goto" } foo: - asm("foo"); // { dg-error "asm" } + asm("foo"); // { dg-error "asm" "" { target c++17_down } } int k; // { dg-error "uninitialized" } A a; // { dg-error "non-literal" } return i; diff --git a/gcc/testsuite/g++.dg/cpp2a/inline-asm1.C b/gcc/testsuite/g++.dg/cpp2a/inline-asm1.C new file mode 100644 index 00000000000..a7835c7199e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/inline-asm1.C @@ -0,0 +1,13 @@ +// P1668R1: Permit unevaluated inline asm in constexpr functions +// PR c++/91346 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +constexpr int +foo (int a, int b) +{ + if (__builtin_is_constant_evaluated ()) + return a + b; + asm (""); // { dg-warning ".asm. in .constexpr. function only available with" "" { target c++17_down } } + return a; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/inline-asm2.C b/gcc/testsuite/g++.dg/cpp2a/inline-asm2.C new file mode 100644 index 00000000000..6038c111eb0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/inline-asm2.C @@ -0,0 +1,17 @@ +// P1668R1: Permit unevaluated inline asm in constexpr functions +// PR c++/91346 +// { dg-do compile { target c++2a } } + +constexpr int +foo (bool b) +{ + if (b) + return 42; + asm (""); // { dg-error "inline assembly is not a constant expression" } +// { dg-message "only unevaluated inline assembly" "" { target *-*-* } .-1 } + return -1; +} + +constexpr int i = foo (true); +static_assert(i == 42, ""); +constexpr int j = foo (false); // { dg-message "in .constexpr. expansion of" } -- 2.30.2