OVL_USING_P (in OVERLOAD)
IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR)
BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (in BASELINK)
+ BIND_EXPR_VEC_DTOR (in BIND_EXPR)
2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
#define BIND_EXPR_TRY_BLOCK(NODE) \
TREE_LANG_FLAG_0 (BIND_EXPR_CHECK (NODE))
+/* This BIND_EXPR is from build_vec_delete_1. */
+#define BIND_EXPR_VEC_DTOR(NODE) \
+ TREE_LANG_FLAG_1 (BIND_EXPR_CHECK (NODE))
+
/* Used to mark the block around the member initializers and cleanups. */
#define BIND_EXPR_BODY_BLOCK(NODE) \
TREE_LANG_FLAG_3 (BIND_EXPR_CHECK (NODE))
they are run on the normal path, but not if they are run on the
exceptional path. We implement this by telling
honor_protect_cleanup_actions to strip the variable cleanup from the
- exceptional path. */
+ exceptional path.
+
+ Another approach could be to make the variable cleanup region enclose
+ initialization, but depend on a flag to indicate that the variable is
+ initialized; that's effectively what we do for arrays. But the current
+ approach works fine for non-arrays, and has no code overhead in the usual
+ case where the temporary destructors are noexcept. */
static void
wrap_temporary_cleanups (tree init, tree guard)
{
+ if (TREE_CODE (guard) == BIND_EXPR)
+ {
+ /* An array cleanup region already encloses any temporary cleanups,
+ don't wrap it around them again. */
+ gcc_checking_assert (BIND_EXPR_VEC_DTOR (guard));
+ return;
+ }
cp_walk_tree_without_duplicates (&init, wrap_cleanups_r, (void *)guard);
}
/* If we're only initializing a single object, guard the
destructors of any temporaries used in its initializer with
- its destructor. But arrays are handled in build_vec_init. */
- if (cleanup && TREE_CODE (type) != ARRAY_TYPE)
+ its destructor. */
+ if (cleanup)
wrap_temporary_cleanups (init, cleanup);
gcc_assert (building_stmt_list_p ());
if (cleanups)
{
for (tree t : *cleanups)
- push_cleanup (decl, t, false);
+ {
+ push_cleanup (decl, t, false);
+ /* As in initialize_local_var. */
+ wrap_temporary_cleanups (init, t);
+ }
release_tree_vector (cleanups);
}
tbase_init = build_stmt (loc, DECL_EXPR, tbase);
controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (controller) = 1;
+ BIND_EXPR_VEC_DTOR (controller) = true;
body = build1 (EXIT_EXPR, void_type_node,
build2 (EQ_EXPR, boolean_type_node, tbase,
--- /dev/null
+// PR c++/53868
+// { dg-do run { target c++11 } }
+
+#if __cplusplus > 201100L
+#define THROWING noexcept(false)
+#else
+#define THROWING
+#endif
+
+extern "C" int printf(const char *, ...);
+extern "C" void abort();
+
+struct SubobjectInA {
+ SubobjectInA();
+ ~SubobjectInA();
+};
+
+int a;
+struct A : SubobjectInA {
+ A() = delete;
+ A(const A &) = delete;
+ A(A &&) = delete;
+ A(int);
+ ~A();
+};
+
+#ifdef DEBUG
+#define TRACE_FUNC( ... ) \
+{ printf("%s\n", __PRETTY_FUNCTION__); __VA_ARGS__ }
+#else
+#define TRACE_FUNC( ... ) \
+{ __VA_ARGS__ }
+#endif
+
+struct Q {
+ Q() : q(0) TRACE_FUNC()
+ ~Q() THROWING;
+ int q;
+};
+
+int main() {
+ try { const A &a = Q().q; }
+ catch (...) { if (!a) return 0; }
+ abort();
+}
+
+SubobjectInA::SubobjectInA() TRACE_FUNC()
+SubobjectInA::~SubobjectInA() TRACE_FUNC()
+A::A(int) TRACE_FUNC(++a;)
+A::~A() TRACE_FUNC(--a;)
+Q::~Q() THROWING TRACE_FUNC( throw 0; )
--- /dev/null
+// { dg-do run { target c++11 } }
+
+struct B { B() {} ~B() noexcept(false) { throw 42; } };
+int a;
+struct A { A() { ++a; }; A(B) { ++a; } ~A() { --a; } };
+
+using Arr = A[3];
+
+int main()
+{
+ try {
+ auto&& ref = Arr{B()};
+ } catch (...) { }
+ return a;
+}