diff mbox series

c++: SFINAE-unfriendly error on throwing pointer [PR112436]

Message ID 20240210202754.2140490-1-polacek@redhat.com
State New
Headers show
Series c++: SFINAE-unfriendly error on throwing pointer [PR112436] | expand

Commit Message

Marek Polacek Feb. 10, 2024, 8:27 p.m. UTC
Probably stage1 material but it should be safe...

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
On the heels of r14-8903, this patch adds further complain parameters
so that we don't emit "invalid use of incomplete type" from inside
a concept.

	PR c++/112436

gcc/cp/ChangeLog:

	* except.cc (expand_start_catch_block): Pass tf_warning_or_error to
	is_admissible_throw_operand_or_catch_parameter.
	(build_throw): Pass complain to
	is_admissible_throw_operand_or_catch_parameter.
	(complete_ptr_ref_or_void_ptr_p): Add a tsubst_flags_t parameter.  Use
	it.  Return bool.  Call complete_type_or_maybe_complain instead of
	complete_type_or_else.
	(is_admissible_throw_operand_or_catch_parameter): Add a tsubst_flags_t
	parameter.  Use it.  Guard error calls.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-pr112436.C: New test.
---
 gcc/cp/except.cc                              | 66 ++++++++++---------
 .../g++.dg/cpp2a/concepts-pr112436.C          |  9 +++
 2 files changed, 44 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C


base-commit: 93e1559bea434a681208e5e7a21513d7da2844d6

Comments

Jason Merrill Feb. 13, 2024, 3:45 a.m. UTC | #1
On 2/10/24 15:27, Marek Polacek wrote:
> Probably stage1 material but it should be safe...

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

Yeah, OK, this should go in along with the 98388 patch.

> -- >8 --
> On the heels of r14-8903, this patch adds further complain parameters
> so that we don't emit "invalid use of incomplete type" from inside
> a concept.
> 
> 	PR c++/112436
> 
> gcc/cp/ChangeLog:
> 
> 	* except.cc (expand_start_catch_block): Pass tf_warning_or_error to
> 	is_admissible_throw_operand_or_catch_parameter.
> 	(build_throw): Pass complain to
> 	is_admissible_throw_operand_or_catch_parameter.
> 	(complete_ptr_ref_or_void_ptr_p): Add a tsubst_flags_t parameter.  Use
> 	it.  Return bool.  Call complete_type_or_maybe_complain instead of
> 	complete_type_or_else.
> 	(is_admissible_throw_operand_or_catch_parameter): Add a tsubst_flags_t
> 	parameter.  Use it.  Guard error calls.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-pr112436.C: New test.
> ---
>   gcc/cp/except.cc                              | 66 ++++++++++---------
>   .../g++.dg/cpp2a/concepts-pr112436.C          |  9 +++
>   2 files changed, 44 insertions(+), 31 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C
> 
> diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
> index ea3d6f57396..f1ffda22fd3 100644
> --- a/gcc/cp/except.cc
> +++ b/gcc/cp/except.cc
> @@ -39,8 +39,8 @@ static tree do_end_catch (tree);
>   static void initialize_handler_parm (tree, tree);
>   static tree do_allocate_exception (tree);
>   static tree wrap_cleanups_r (tree *, int *, void *);
> -static int complete_ptr_ref_or_void_ptr_p (tree, tree);
> -static bool is_admissible_throw_operand_or_catch_parameter (tree, bool);
> +static bool is_admissible_throw_operand_or_catch_parameter (tree, bool,
> +							    tsubst_flags_t);
>   
>   /* Sets up all the global eh stuff that needs to be initialized at the
>      start of compilation.  */
> @@ -398,7 +398,8 @@ expand_start_catch_block (tree decl)
>   
>     if (decl)
>       {
> -      if (!is_admissible_throw_operand_or_catch_parameter (decl, false))
> +      if (!is_admissible_throw_operand_or_catch_parameter (decl, false,
> +							   tf_warning_or_error))
>   	decl = error_mark_node;
>   
>         type = prepare_eh_type (TREE_TYPE (decl));
> @@ -626,11 +627,10 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain)
>       warning_at (loc, 0,
>   		"throwing NULL, which has integral, not pointer type");
>   
> -  if (exp != NULL_TREE)
> -    {
> -      if (!is_admissible_throw_operand_or_catch_parameter (exp, true))
> -	return error_mark_node;
> -    }
> +  if (exp && !is_admissible_throw_operand_or_catch_parameter (exp,
> +							      /*is_throw=*/true,
> +							      complain))
> +    return error_mark_node;
>   
>     if (! doing_eh ())
>       return error_mark_node;
> @@ -815,28 +815,26 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain)
>      Return the zero on failure and nonzero on success. FROM can be
>      the expr or decl from whence TYPE came, if available.  */
>   
> -static int
> -complete_ptr_ref_or_void_ptr_p (tree type, tree from)
> +static bool
> +complete_ptr_ref_or_void_ptr_p (tree type, tree from, tsubst_flags_t complain)
>   {
> -  int is_ptr;
> -
>     /* Check complete.  */
> -  type = complete_type_or_else (type, from);
> +  type = complete_type_or_maybe_complain (type, from, complain);
>     if (!type)
> -    return 0;
> +    return false;
>   
>     /* Or a pointer or ref to one, or cv void *.  */
> -  is_ptr = TYPE_PTR_P (type);
> +  const bool is_ptr = TYPE_PTR_P (type);
>     if (is_ptr || TYPE_REF_P (type))
>       {
>         tree core = TREE_TYPE (type);
>   
>         if (is_ptr && VOID_TYPE_P (core))
>   	/* OK */;
> -      else if (!complete_type_or_else (core, from))
> -	return 0;
> +      else if (!complete_type_or_maybe_complain (core, from, complain))
> +	return false;
>       }
> -  return 1;
> +  return true;
>   }
>   
>   /* If IS_THROW is true return truth-value if T is an expression admissible
> @@ -846,13 +844,14 @@ complete_ptr_ref_or_void_ptr_p (tree type, tree from)
>      for its type plus rvalue reference type is also not admissible.  */
>   
>   static bool
> -is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
> +is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw,
> +						tsubst_flags_t complain)
>   {
>     tree expr = is_throw ? t : NULL_TREE;
>     tree type = TREE_TYPE (t);
>   
>     /* C++11 [except.handle] The exception-declaration shall not denote
> -     an incomplete type, an abstract class type, or an rvalue reference
> +     an incomplete type, an abstract class type, or an rvalue reference
>        type.  */
>   
>     /* 15.1/4 [...] The type of the throw-expression shall not be an
> @@ -862,7 +861,7 @@ is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
>   	    restrictions on type matching mentioned in 15.3, the operand
>   	    of throw is treated exactly as a function argument in a call
>   	    (5.2.2) or the operand of a return statement.  */
> -  if (!complete_ptr_ref_or_void_ptr_p (type, expr))
> +  if (!complete_ptr_ref_or_void_ptr_p (type, expr, complain))
>       return false;
>   
>     tree nonref_type = non_reference (type);
> @@ -872,25 +871,30 @@ is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
>     /* 10.4/3 An abstract class shall not be used as a parameter type,
>   	    as a function return type or as type of an explicit
>   	    conversion.  */
> -  else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
> +  else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type,
> +				    complain))
>       return false;
>     else if (!is_throw
>   	   && TYPE_REF_P (type)
>   	   && TYPE_REF_IS_RVALUE (type))
>       {
> -      error ("cannot declare %<catch%> parameter to be of rvalue "
> -	     "reference type %qT", type);
> +      if (complain & tf_error)
> +	error ("cannot declare %<catch%> parameter to be of rvalue "
> +	       "reference type %qT", type);
>         return false;
>       }
>     else if (variably_modified_type_p (type, NULL_TREE))
>       {
> -      if (is_throw)
> -	error_at (cp_expr_loc_or_input_loc (expr),
> -		  "cannot throw expression of type %qT because it involves "
> -		  "types of variable size", type);
> -      else
> -	error ("cannot catch type %qT because it involves types of "
> -	       "variable size", type);
> +      if (complain & tf_error)
> +	{
> +	  if (is_throw)
> +	    error_at (cp_expr_loc_or_input_loc (expr),
> +		      "cannot throw expression of type %qT because it involves "
> +		      "types of variable size", type);
> +	  else
> +	    error ("cannot catch type %qT because it involves types of "
> +		   "variable size", type);
> +	}
>         return false;
>       }
>   
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C
> new file mode 100644
> index 00000000000..6b755e5ed70
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C
> @@ -0,0 +1,9 @@
> +// PR c++/112436
> +// { dg-do compile { target c++20 } }
> +
> +template<class T>
> +concept Throwable = requires { throw T(); };
> +struct Incomplete;
> +
> +static_assert(!Throwable<Incomplete*>);
> +static_assert(!Throwable<int(*)[]>);
> 
> base-commit: 93e1559bea434a681208e5e7a21513d7da2844d6
diff mbox series

Patch

diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index ea3d6f57396..f1ffda22fd3 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -39,8 +39,8 @@  static tree do_end_catch (tree);
 static void initialize_handler_parm (tree, tree);
 static tree do_allocate_exception (tree);
 static tree wrap_cleanups_r (tree *, int *, void *);
-static int complete_ptr_ref_or_void_ptr_p (tree, tree);
-static bool is_admissible_throw_operand_or_catch_parameter (tree, bool);
+static bool is_admissible_throw_operand_or_catch_parameter (tree, bool,
+							    tsubst_flags_t);
 
 /* Sets up all the global eh stuff that needs to be initialized at the
    start of compilation.  */
@@ -398,7 +398,8 @@  expand_start_catch_block (tree decl)
 
   if (decl)
     {
-      if (!is_admissible_throw_operand_or_catch_parameter (decl, false))
+      if (!is_admissible_throw_operand_or_catch_parameter (decl, false,
+							   tf_warning_or_error))
 	decl = error_mark_node;
 
       type = prepare_eh_type (TREE_TYPE (decl));
@@ -626,11 +627,10 @@  build_throw (location_t loc, tree exp, tsubst_flags_t complain)
     warning_at (loc, 0,
 		"throwing NULL, which has integral, not pointer type");
 
-  if (exp != NULL_TREE)
-    {
-      if (!is_admissible_throw_operand_or_catch_parameter (exp, true))
-	return error_mark_node;
-    }
+  if (exp && !is_admissible_throw_operand_or_catch_parameter (exp,
+							      /*is_throw=*/true,
+							      complain))
+    return error_mark_node;
 
   if (! doing_eh ())
     return error_mark_node;
@@ -815,28 +815,26 @@  build_throw (location_t loc, tree exp, tsubst_flags_t complain)
    Return the zero on failure and nonzero on success. FROM can be
    the expr or decl from whence TYPE came, if available.  */
 
-static int
-complete_ptr_ref_or_void_ptr_p (tree type, tree from)
+static bool
+complete_ptr_ref_or_void_ptr_p (tree type, tree from, tsubst_flags_t complain)
 {
-  int is_ptr;
-
   /* Check complete.  */
-  type = complete_type_or_else (type, from);
+  type = complete_type_or_maybe_complain (type, from, complain);
   if (!type)
-    return 0;
+    return false;
 
   /* Or a pointer or ref to one, or cv void *.  */
-  is_ptr = TYPE_PTR_P (type);
+  const bool is_ptr = TYPE_PTR_P (type);
   if (is_ptr || TYPE_REF_P (type))
     {
       tree core = TREE_TYPE (type);
 
       if (is_ptr && VOID_TYPE_P (core))
 	/* OK */;
-      else if (!complete_type_or_else (core, from))
-	return 0;
+      else if (!complete_type_or_maybe_complain (core, from, complain))
+	return false;
     }
-  return 1;
+  return true;
 }
 
 /* If IS_THROW is true return truth-value if T is an expression admissible
@@ -846,13 +844,14 @@  complete_ptr_ref_or_void_ptr_p (tree type, tree from)
    for its type plus rvalue reference type is also not admissible.  */
 
 static bool
-is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
+is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw,
+						tsubst_flags_t complain)
 {
   tree expr = is_throw ? t : NULL_TREE;
   tree type = TREE_TYPE (t);
 
   /* C++11 [except.handle] The exception-declaration shall not denote
-     an incomplete type, an abstract class type, or an rvalue reference 
+     an incomplete type, an abstract class type, or an rvalue reference
      type.  */
 
   /* 15.1/4 [...] The type of the throw-expression shall not be an
@@ -862,7 +861,7 @@  is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
 	    restrictions on type matching mentioned in 15.3, the operand
 	    of throw is treated exactly as a function argument in a call
 	    (5.2.2) or the operand of a return statement.  */
-  if (!complete_ptr_ref_or_void_ptr_p (type, expr))
+  if (!complete_ptr_ref_or_void_ptr_p (type, expr, complain))
     return false;
 
   tree nonref_type = non_reference (type);
@@ -872,25 +871,30 @@  is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
   /* 10.4/3 An abstract class shall not be used as a parameter type,
 	    as a function return type or as type of an explicit
 	    conversion.  */
-  else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
+  else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type,
+				    complain))
     return false;
   else if (!is_throw
 	   && TYPE_REF_P (type)
 	   && TYPE_REF_IS_RVALUE (type))
     {
-      error ("cannot declare %<catch%> parameter to be of rvalue "
-	     "reference type %qT", type);
+      if (complain & tf_error)
+	error ("cannot declare %<catch%> parameter to be of rvalue "
+	       "reference type %qT", type);
       return false;
     }
   else if (variably_modified_type_p (type, NULL_TREE))
     {
-      if (is_throw)
-	error_at (cp_expr_loc_or_input_loc (expr),
-		  "cannot throw expression of type %qT because it involves "
-		  "types of variable size", type);
-      else
-	error ("cannot catch type %qT because it involves types of "
-	       "variable size", type);
+      if (complain & tf_error)
+	{
+	  if (is_throw)
+	    error_at (cp_expr_loc_or_input_loc (expr),
+		      "cannot throw expression of type %qT because it involves "
+		      "types of variable size", type);
+	  else
+	    error ("cannot catch type %qT because it involves types of "
+		   "variable size", type);
+	}
       return false;
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C
new file mode 100644
index 00000000000..6b755e5ed70
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C
@@ -0,0 +1,9 @@ 
+// PR c++/112436
+// { dg-do compile { target c++20 } }
+
+template<class T>
+concept Throwable = requires { throw T(); };
+struct Incomplete;
+
+static_assert(!Throwable<Incomplete*>);
+static_assert(!Throwable<int(*)[]>);