aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2024-02-10 10:52:18 -0500
committerMarek Polacek <polacek@redhat.com>2024-02-13 08:54:08 -0500
commitecc119effe1aa445cb973c8cbb5ef3830f256f13 (patch)
tree93a9da6e9cff14b42d0d78f116165d7daa5ce470 /gcc
parent4a1cd5560b9b545eb848eb1d1e06d345fb606f76 (diff)
downloadgcc-ecc119effe1aa445cb973c8cbb5ef3830f256f13.zip
gcc-ecc119effe1aa445cb973c8cbb5ef3830f256f13.tar.gz
gcc-ecc119effe1aa445cb973c8cbb5ef3830f256f13.tar.bz2
c++: SFINAE-unfriendly error on throwing pointer [PR112436]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/except.cc66
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-pr112436.C9
2 files changed, 44 insertions, 31 deletions
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index ea3d6f5..f1ffda22 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 0000000..6b755e5
--- /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(*)[]>);