This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: C++ PATCH for c++/91346 - Implement C++2a P1668R1, allow unevaluated asm in constexpr


On Tue, Aug 06, 2019 at 09:25:45PM -0400, Jason Merrill wrote:
> Let's downgrade the errors in earlier standard modes to pedwarn. Ok with
> that change.

Works for me, here's what I'll apply once it passes testing.

I removed the diagnostic in potential_constant_expression_1/ASM_EXPR so that
we don't generate duplicate pedwarns for the same thing.  Hope that's OK.

2019-08-07  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.
	* 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.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 36a66337433..e86b0789b84 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,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 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 4d07a6a3011..ccf89f0856f 100644
--- gcc/cp/parser.c
+++ 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 ("%<asm%> in %<constexpr%> function");
-      cp_function_chain->invalid_constexpr = true;
-    }
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+      && (cxx_dialect < cxx2a))
+    pedwarn (asm_loc, 0, "%<asm%> in %<constexpr%> 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 gcc/cp/pt.c gcc/cp/pt.c
index b1ad99d1481..b03968febb4 100644
--- gcc/cp/pt.c
+++ 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 gcc/cp/semantics.c gcc/cp/semantics.c
index 77e7a6dced2..8fe632f2239 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..a7835c7199e
--- /dev/null
+++ 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 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" }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]