@@ -1294,26 +1294,35 @@ maybe_set_retval_sentinel ()
current_retval_sentinel, boolean_true_node);
}
-/* COMPOUND_STMT is the STATEMENT_LIST for the current function body. If
- current_retval_sentinel was set in this function, wrap the body in a
- CLEANUP_STMT to destroy the return value on throw. */
+/* COMPOUND_STMT is the STATEMENT_LIST for some block. If COMPOUND_STMT is the
+ current function body or a try block, and current_retval_sentinel was set in
+ this function, wrap the block in a CLEANUP_STMT to destroy the return value
+ on throw. */
void
maybe_splice_retval_cleanup (tree compound_stmt)
{
- /* If need_retval_cleanup set current_retval_sentinel, wrap the function body
- in a CLEANUP_STMT to handle destroying the return value. */
- if (!DECL_CONSTRUCTOR_P (current_function_decl)
+ /* If we need a cleanup for the return value, add it in at the same level as
+ pushdecl_outermost_localscope. And also in try blocks. */
+ bool function_body
+ = (current_binding_level->level_chain
+ && current_binding_level->level_chain->kind == sk_function_parms);
+
+ if ((function_body || current_binding_level->kind == sk_try)
+ && !DECL_CONSTRUCTOR_P (current_function_decl)
&& !DECL_DESTRUCTOR_P (current_function_decl)
&& current_retval_sentinel)
{
location_t loc = DECL_SOURCE_LOCATION (current_function_decl);
-
- /* Add a DECL_EXPR for current_retval_sentinel. */
tree_stmt_iterator iter = tsi_start (compound_stmt);
tree retval = DECL_RESULT (current_function_decl);
- tree decl_expr = build_stmt (loc, DECL_EXPR, current_retval_sentinel);
- tsi_link_before (&iter, decl_expr, TSI_SAME_STMT);
+
+ if (function_body)
+ {
+ /* Add a DECL_EXPR for current_retval_sentinel. */
+ tree decl_expr = build_stmt (loc, DECL_EXPR, current_retval_sentinel);
+ tsi_link_before (&iter, decl_expr, TSI_SAME_STMT);
+ }
/* Skip past other decls, they can't contain a return. */
while (TREE_CODE (tsi_stmt (iter)) == DECL_EXPR)
@@ -12751,9 +12751,6 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
/* Parse an (optional) statement-seq. */
cp_parser_statement_seq_opt (parser, in_statement_expr);
- if (function_body)
- maybe_splice_retval_cleanup (compound_stmt);
-
/* Consume the `}'. */
braces.require_close (parser);
@@ -624,6 +624,8 @@ do_poplevel (tree stmt_list)
{
tree block = NULL;
+ maybe_splice_retval_cleanup (stmt_list);
+
if (stmts_are_full_exprs_p ())
block = poplevel (kept_level_p (), 1, 0);
new file mode 100644
@@ -0,0 +1,12 @@
+// PR c++/102191
+// { dg-do compile { target c++20 } }
+
+struct X {
+ struct A {
+ constexpr ~A() noexcept(false) { }
+ };
+
+ constexpr A operator()(auto...) { return {}; }
+};
+
+void f() { []() consteval { X{}(); }(); }
@@ -11,13 +11,16 @@ int c, d;
#define THROWS
#endif
+extern "C" int printf (const char *, ...);
+#define DEBUG // printf ("%p %s\n", this, __PRETTY_FUNCTION__)
+
struct X
{
- X(bool throws) : throws_(throws) { ++c; }
- X(const X& x) : throws_(x.throws_) { ++c; }
+ X(bool throws) : throws_(throws) { ++c; DEBUG; }
+ X(const X& x); // not defined
~X() THROWS
{
- ++d;
+ ++d; DEBUG;
if (throws_) { throw 1; }
}
private:
@@ -42,6 +45,40 @@ void h()
#endif
}
+X i()
+{
+ try {
+ X x(true);
+ return X(false);
+ } catch(...) {}
+ return X(false);
+}
+
+X j()
+{
+ try {
+ return X(true),X(false);
+ } catch(...) {}
+ return X(false);
+}
+
+template <class T>
+T k()
+{
+ try {
+ return T(true),T(false);
+ } catch (...) {}
+ return T(true),T(false);
+}
+
+X l() try { return X(true),X(false); }
+ catch (...) { return X(true),X(false); }
+
+template <class T>
+T m()
+ try { return T(true),T(false); }
+ catch (...) { return T(true),T(false); }
+
int main()
{
try { f(); }
@@ -53,6 +90,15 @@ int main()
try { h(); }
catch (...) {}
- if (c != d)
- throw;
+ try { i(); }
+ catch (...) {}
+
+ try { j(); } catch (...) {}
+
+ try { k<X>(); } catch (...) {}
+
+ try { l(); } catch (...) {}
+ try { m<X>(); } catch (...) {}
+
+ return c - d;
}