C++ PATCH for c++/91346 - Implement C++2a P1668R1, allow unevaluated asm in constexpr
Marek Polacek
polacek@redhat.com
Tue Aug 6 14:56:00 GMT 2019
This patch implements another C++2a feature, P1668R1: Permit unevaluated inline
asm in constexpr functions.
It's really straightforward so not much to say; we need to allow ASM_EXPRs in
potential_constant_expression_1, but since only unevaluated asm is allowed,
cxx_eval_constant_expression must give an error when it encounters an ASM_EXPR.
I've improved location for "asm", so that the error points to "asm" rather than
to ";".
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2019-08-06 Marek Polacek <polacek@redhat.com>
PR c++/91346 - Implement P1668R1, allow unevaluated asm in constexpr.
* constexpr.c (cxx_eval_constant_expression): Handle ASM_EXPR.
(potential_constant_expression_1) <case ASM_EXPR>: Allow in C++2a, give
an error otherwise.
* cp-tree.h (finish_asm_stmt): Adjust.
* parser.c (cp_parser_asm_definition): Grab the locaion of "asm" and
use it. Adjust an error message. Allow asm in C++2a.
* 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.
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 36a66337433..d45e65df400 100644
--- gcc/cp/constexpr.c
+++ 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 "
+ "%<constexpr%> function in C++2a");
+ }
+ *non_constant_p = true;
+ return t;
+
default:
if (STATEMENT_CODE_P (TREE_CODE (t)))
{
@@ -6469,13 +6481,22 @@ 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:
+ if (cxx_dialect >= cxx2a)
+ /* In C++2a, unevaluated inline assembly is permitted in constexpr
+ functions. */
+ return true;
+ else if (flags & tf_error)
+ error_at (loc, "inline assembly is not allowed in %<constexpr%> "
+ "functions before C++2a");
+ return false;
+
case OBJ_TYPE_REF:
if (cxx_dialect >= cxx2a)
/* In C++2a virtual calls can be constexpr, don't give up yet. */
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index d4e67cdfd96..72ee1d61e97 100644
--- gcc/cp/cp-tree.h
+++ 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 gcc/cp/parser.c gcc/cp/parser.c
index 79da7b52eb9..2d0e6a0c931 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -19817,14 +19817,19 @@ 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);
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ /* In C++2a, unevaluated inline assembly is permitted in constexpr
+ functions. */
+ && (cxx_dialect < cxx2a))
{
- error ("%<asm%> in %<constexpr%> function");
+ error_at (asm_loc, "%<asm%> in %<constexpr%> function only available "
+ "with %<-std=c++2a%> or %<-std=gnu++2a%>");
cp_function_chain->invalid_constexpr = true;
}
@@ -20032,7 +20037,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 gcc/cp/pt.c gcc/cp/pt.c
index 903e589b663..85cff96c1b6 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -17394,8 +17394,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 gcc/cp/semantics.c gcc/cp/semantics.c
index fa6962454bf..83dc122e0bd 100644
--- gcc/cp/semantics.c
+++ 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 %<asm%> operand %qE could not be determined",
- TREE_VALUE (t));
+ error_at (loc,
+ "type of %<asm%> 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 gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C
index ae3dcc69cf0..d82dbada1bf 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-neg1.C
+++ 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 gcc/testsuite/g++.dg/cpp2a/inline-asm1.C gcc/testsuite/g++.dg/cpp2a/inline-asm1.C
new file mode 100644
index 00000000000..9ac588f0ecc
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/inline-asm1.C
@@ -0,0 +1,12 @@
+// P1668R1: Permit unevaluated inline asm in constexpr functions
+// PR c++/91346
+// { dg-do compile { target c++11 } }
+
+constexpr int
+foo (int a, int b)
+{
+ if (__builtin_is_constant_evaluated ())
+ return a + b;
+ asm (""); // { dg-error ".asm. in .constexpr. function only available with" "" { target c++17_down } }
+ return a;
+}
diff --git gcc/testsuite/g++.dg/cpp2a/inline-asm2.C gcc/testsuite/g++.dg/cpp2a/inline-asm2.C
new file mode 100644
index 00000000000..6038c111eb0
--- /dev/null
+++ 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" }
More information about the Gcc-patches
mailing list