aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2024-02-06 15:35:16 -0500
committerMarek Polacek <polacek@redhat.com>2024-02-09 16:37:37 -0500
commit3a3e0f1b46a3ad71ebeedc419393e3a36f1ce6db (patch)
tree63cfed92cbd452f83e5e6457ac9c633d201d7f14
parentb3d622d70ba209b63471fc1b0970870046e55745 (diff)
downloadgcc-3a3e0f1b46a3ad71ebeedc419393e3a36f1ce6db.zip
gcc-3a3e0f1b46a3ad71ebeedc419393e3a36f1ce6db.tar.gz
gcc-3a3e0f1b46a3ad71ebeedc419393e3a36f1ce6db.tar.bz2
c++: make build_throw SFINAE-friendly [PR98388]
Here the problem is that we give hard errors while substituting template parameters during overload resolution of is_throwable which has an invalid throw in decltype. The backtrace shows that fn_type_unification -> instantiate_template -> tsubst* passes complain=0 as expected, but build_throw doesn't have a complain parameter. So let's add one. Also remove a redundant local variable which I should have removed in my P2266 patch. There's still one problem for which I opened <https://gcc.gnu.org/PR113853>. We need to patch up treat_lvalue_as_rvalue_p and remove the dg-bogus. Thanks to Patrick for notifying me of this PR. This doesn't fully fix 113789; there I think I'll have to figure our why a candidate wasn't discarded from the overload set. PR c++/98388 gcc/cp/ChangeLog: * coroutines.cc (coro_rewrite_function_body): Pass tf_warning_or_error to build_throw. (morph_fn_to_coro): Likewise. * cp-tree.h (build_throw): Adjust. * except.cc (expand_end_catch_block): Pass tf_warning_or_error to build_throw. (build_throw): Add a tsubst_flags_t parameter. Use it. Remove redundant variable. Guard an inform call. * parser.cc (cp_parser_throw_expression): Pass tf_warning_or_error to build_throw. * pt.cc (tsubst_expr) <case THROW_EXPR>: Pass complain to build_throw. libcc1/ChangeLog: * libcp1plugin.cc (plugin_build_unary_expr): Pass tf_error to build_throw. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/sfinae69.C: New test.
-rw-r--r--gcc/cp/coroutines.cc4
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/except.cc33
-rw-r--r--gcc/cp/parser.cc2
-rw-r--r--gcc/cp/pt.cc2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae69.C21
-rw-r--r--libcc1/libcp1plugin.cc4
7 files changed, 43 insertions, 26 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3194c91..9b037ed 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -4246,7 +4246,7 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig,
boolean_type_node, i_a_r_c);
finish_if_stmt_cond (not_iarc, not_iarc_if);
/* If the initial await resume called value is false, rethrow... */
- tree rethrow = build_throw (fn_start, NULL_TREE);
+ tree rethrow = build_throw (fn_start, NULL_TREE, tf_warning_or_error);
suppress_warning (rethrow);
finish_expr_stmt (rethrow);
finish_then_clause (not_iarc_if);
@@ -5151,7 +5151,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
tree del_coro_fr = coro_get_frame_dtor (coro_fp, orig, frame_size,
promise_type, fn_start);
finish_expr_stmt (del_coro_fr);
- tree rethrow = build_throw (fn_start, NULL_TREE);
+ tree rethrow = build_throw (fn_start, NULL_TREE, tf_warning_or_error);
suppress_warning (rethrow);
finish_expr_stmt (rethrow);
finish_handler (handler);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 969c723..334c113 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7185,7 +7185,8 @@ extern void init_exception_processing (void);
extern tree expand_start_catch_block (tree);
extern void expand_end_catch_block (void);
extern tree build_exc_ptr (void);
-extern tree build_throw (location_t, tree);
+extern tree build_throw (location_t, tree,
+ tsubst_flags_t);
extern int nothrow_libfn_p (const_tree);
extern void check_handlers (tree);
extern tree finish_noexcept_expr (tree, tsubst_flags_t);
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index d17a57d..ea3d6f5 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -486,7 +486,8 @@ expand_end_catch_block (void)
|| DECL_DESTRUCTOR_P (current_function_decl))
&& !in_nested_catch ())
{
- tree rethrow = build_throw (input_location, NULL_TREE);
+ tree rethrow = build_throw (input_location, NULL_TREE,
+ tf_warning_or_error);
/* Disable all warnings for the generated rethrow statement. */
suppress_warning (rethrow);
finish_expr_stmt (rethrow);
@@ -607,7 +608,7 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/)
/* Build a throw expression. */
tree
-build_throw (location_t loc, tree exp)
+build_throw (location_t loc, tree exp, tsubst_flags_t complain)
{
if (exp == error_mark_node)
return exp;
@@ -621,7 +622,7 @@ build_throw (location_t loc, tree exp)
return exp;
}
- if (exp && null_node_p (exp))
+ if (exp && null_node_p (exp) && (complain & tf_warning))
warning_at (loc, 0,
"throwing NULL, which has integral, not pointer type");
@@ -642,8 +643,6 @@ build_throw (location_t loc, tree exp)
tree object, ptr;
tree allocate_expr;
- tsubst_flags_t complain = tf_warning_or_error;
-
/* The CLEANUP_TYPE is the internal type of a destructor. */
if (!cleanup_type)
{
@@ -714,7 +713,6 @@ build_throw (location_t loc, tree exp)
if (CLASS_TYPE_P (temp_type))
{
int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
- bool converted = false;
location_t exp_loc = cp_expr_loc_or_loc (exp, loc);
/* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes
@@ -727,23 +725,20 @@ build_throw (location_t loc, tree exp)
exp = moved;
/* Call the copy constructor. */
- if (!converted)
- {
- releasing_vec exp_vec (make_tree_vector_single (exp));
- exp = (build_special_member_call
- (object, complete_ctor_identifier, &exp_vec,
- TREE_TYPE (object), flags, tf_warning_or_error));
- }
-
+ releasing_vec exp_vec (make_tree_vector_single (exp));
+ exp = build_special_member_call (object, complete_ctor_identifier,
+ &exp_vec, TREE_TYPE (object), flags,
+ complain);
if (exp == error_mark_node)
{
- inform (exp_loc, " in thrown expression");
+ if (complain & tf_error)
+ inform (exp_loc, " in thrown expression");
return error_mark_node;
}
}
else
{
- tree tmp = decay_conversion (exp, tf_warning_or_error);
+ tree tmp = decay_conversion (exp, complain);
if (tmp == error_mark_node)
return error_mark_node;
exp = cp_build_init_expr (object, tmp);
@@ -768,7 +763,7 @@ build_throw (location_t loc, tree exp)
tree binfo = TYPE_BINFO (TREE_TYPE (object));
tree dtor_fn = lookup_fnfields (binfo,
complete_dtor_identifier, 0,
- tf_warning_or_error);
+ complain);
dtor_fn = BASELINK_FUNCTIONS (dtor_fn);
if (!mark_used (dtor_fn)
|| !perform_or_defer_access_check (binfo, dtor_fn,
@@ -785,7 +780,7 @@ build_throw (location_t loc, tree exp)
cleanup = build_int_cst (cleanup_type, 0);
/* ??? Indicate that this function call throws throw_type. */
- tree tmp = cp_build_function_call_nary (throw_fn, tf_warning_or_error,
+ tree tmp = cp_build_function_call_nary (throw_fn, complain,
ptr, throw_type, cleanup,
NULL_TREE);
@@ -807,7 +802,7 @@ build_throw (location_t loc, tree exp)
/* ??? Indicate that this function call allows exceptions of the type
of the enclosing catch block (if known). */
- exp = cp_build_function_call_vec (rethrow_fn, NULL, tf_warning_or_error);
+ exp = cp_build_function_call_vec (rethrow_fn, NULL, complain);
}
exp = build1_loc (loc, THROW_EXPR, void_type_node, exp);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c4292c4..09ecfa2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -29310,7 +29310,7 @@ cp_parser_throw_expression (cp_parser* parser)
the end at the end of the final token we consumed. */
location_t combined_loc = make_location (start_loc, start_loc,
parser->lexer);
- expression = build_throw (combined_loc, expression);
+ expression = build_throw (combined_loc, expression, tf_warning_or_error);
return expression;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f9abb21..9c225c0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21180,7 +21180,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case THROW_EXPR:
RETURN (build_throw
- (input_location, RECUR (TREE_OPERAND (t, 0))));
+ (input_location, RECUR (TREE_OPERAND (t, 0)), complain));
case CONSTRUCTOR:
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae69.C b/gcc/testsuite/g++.dg/cpp0x/sfinae69.C
new file mode 100644
index 0000000..361e0b7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae69.C
@@ -0,0 +1,21 @@
+// PR c++/98388
+// { dg-do compile { target c++11 } }
+
+struct moveonly {
+ moveonly() = default;
+ moveonly(moveonly&&) = default;
+};
+
+template<class T>
+constexpr auto is_throwable(T t) -> decltype(throw t, true) {
+ return true;
+}
+template<class T>
+constexpr bool is_throwable(...) { return false; }
+
+constexpr bool b = is_throwable<moveonly>(moveonly{});
+#if __cplusplus >= 202002L
+static_assert (b, "move from the function parameter"); // { dg-bogus "" "PR113853" { xfail c++20 } }
+#else
+static_assert (!b, "no move from the function parameter");
+#endif
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index 7f4e4c9..0eff7c6 100644
--- a/libcc1/libcp1plugin.cc
+++ b/libcc1/libcp1plugin.cc
@@ -2640,7 +2640,7 @@ plugin_build_unary_expr (cc1_plugin::connection *self,
break;
case THROW_EXPR:
- result = build_throw (input_location, op0);
+ result = build_throw (input_location, op0, tf_error);
break;
case TYPEID_EXPR:
@@ -2664,7 +2664,7 @@ plugin_build_unary_expr (cc1_plugin::connection *self,
result = make_pack_expansion (op0);
break;
- // We're using this for sizeof...(pack). */
+ /* We're using this for sizeof...(pack). */
case TYPE_PACK_EXPANSION:
result = make_pack_expansion (op0);
PACK_EXPANSION_SIZEOF_P (result) = true;