Commit 14af5d9b by Jason Merrill

c++: Partially revert patch for PR66139.

The patch for 66139 exposed a long-standing bug with
split_nonconstant_init (since 4.7, apparently): initializion of individual
elements of an aggregate are not a full-expressions, but
split_nonconstant_init was making full-expressions out of them.  My fix for
66139 extended the use of split_nonconstant_init, and thus the bug, to
aggregate initialization of temporaries within an expression, in which
context (PR94041) the bug is more noticeable.  PR93922 is a problem with my
implementation strategy of splitting out at gimplification time, introducing
function calls that weren't in the GENERIC.  So I'm going to revert the
patch now and try again for GCC 11.

gcc/cp/ChangeLog
2020-03-10  Jason Merrill  <jason@redhat.com>

	PR c++/93922
	PR c++/94041
	PR c++/52320
	PR c++/66139
	* cp-gimplify.c (cp_gimplify_init_expr): Partially revert patch for
	66139: Don't split_nonconstant_init.  Remove pre_p parameter.
parent e00cb200
2020-03-10 Jason Merrill <jason@redhat.com>
PR c++/93922
PR c++/94041
PR c++/52320
PR c++/66139
* cp-gimplify.c (cp_gimplify_init_expr): Partially revert patch for
66139: Don't split_nonconstant_init. Remove pre_p parameter.
2020-03-09 Marek Polacek <polacek@redhat.com> 2020-03-09 Marek Polacek <polacek@redhat.com>
PR c++/92031 - bogus taking address of rvalue error. PR c++/92031 - bogus taking address of rvalue error.
......
...@@ -513,7 +513,7 @@ gimplify_expr_stmt (tree *stmt_p) ...@@ -513,7 +513,7 @@ gimplify_expr_stmt (tree *stmt_p)
/* Gimplify initialization from an AGGR_INIT_EXPR. */ /* Gimplify initialization from an AGGR_INIT_EXPR. */
static void static void
cp_gimplify_init_expr (tree *expr_p, gimple_seq *pre_p) cp_gimplify_init_expr (tree *expr_p)
{ {
tree from = TREE_OPERAND (*expr_p, 1); tree from = TREE_OPERAND (*expr_p, 1);
tree to = TREE_OPERAND (*expr_p, 0); tree to = TREE_OPERAND (*expr_p, 0);
...@@ -526,22 +526,6 @@ cp_gimplify_init_expr (tree *expr_p, gimple_seq *pre_p) ...@@ -526,22 +526,6 @@ cp_gimplify_init_expr (tree *expr_p, gimple_seq *pre_p)
if (TREE_CODE (from) == TARGET_EXPR && TARGET_EXPR_INITIAL (from)) if (TREE_CODE (from) == TARGET_EXPR && TARGET_EXPR_INITIAL (from))
from = TARGET_EXPR_INITIAL (from); from = TARGET_EXPR_INITIAL (from);
/* If we might need to clean up a partially constructed object, break down
the CONSTRUCTOR with split_nonconstant_init. */
if (TREE_CODE (from) == CONSTRUCTOR
&& flag_exceptions
&& TREE_SIDE_EFFECTS (from)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (to)))
{
gimplify_expr (&to, pre_p, NULL, is_gimple_lvalue, fb_lvalue);
replace_placeholders (from, to);
from = split_nonconstant_init (to, from);
cp_genericize_tree (&from, false);
copy_if_shared (&from);
*expr_p = from;
return;
}
/* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them
inside the TARGET_EXPR. */ inside the TARGET_EXPR. */
for (t = from; t; ) for (t = from; t; )
...@@ -734,7 +718,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) ...@@ -734,7 +718,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
LHS of an assignment might also be involved in the RHS, as in bug LHS of an assignment might also be involved in the RHS, as in bug
25979. */ 25979. */
case INIT_EXPR: case INIT_EXPR:
cp_gimplify_init_expr (expr_p, pre_p); cp_gimplify_init_expr (expr_p);
if (TREE_CODE (*expr_p) != INIT_EXPR) if (TREE_CODE (*expr_p) != INIT_EXPR)
return GS_OK; return GS_OK;
/* Fall through. */ /* Fall through. */
......
// PR c++/66139
// { dg-do run { target c++11 } }
int constructed = 0;
class lock_guard_ext{
public:
lock_guard_ext() { ++constructed; }
~lock_guard_ext() { --constructed; }
};
struct Access {
lock_guard_ext lock;
int value;
};
int t() {
throw 0;
}
Access foo1() {
return { {}, t() };
}
int main () {
try { foo1(); } catch (int) {}
if (constructed != 0)
__builtin_abort();
}
// PR c++/66139
// { dg-do run { target c++11 } }
#include <initializer_list>
int c, d;
struct a
{
a (int i) { if (i) throw i; c++; }
~a () { d++; }
};
void check (void (*f) ())
{
try
{
c = d = 0;
f ();
}
catch (int)
{
if (c != 1 || d != 1)
__builtin_abort ();
return;
}
__builtin_abort ();
}
int main ()
{
struct s { a x, y; };
check ([] { s t { 0, 1 }; });
check ([] { s { 0, 1 }; });
check ([] { a t[2] { 0, 1 }; });
using array = a[2];
check ([] { array { 0, 1 }; });
check ([] { std::initializer_list <a> t { 0, 1 }; });
check ([] { std::initializer_list <a> { 0, 1 }; });
}
// Test that we properly clean up if we get an exception in the middle of
// constructing the closure object.
// { dg-do run }
// { dg-require-effective-target c++11 }
struct A
{
A() {}
A(const A&) { throw 1; }
};
int bs;
struct B
{
B() { ++bs; }
B(const B&) { ++bs; }
~B() { --bs; }
};
int main()
{
{
B b1, b2;
A a;
try
{
[b1, a, b2]{ };
}
catch(...) {}
}
return bs;
}
// PR c++/52320
// { dg-do run }
#if DEBUG
extern "C" int printf (const char *, ...);
#define FUNCTION_NAME __PRETTY_FUNCTION__
#define TRACE_FUNCTION printf ("%p->%s\n", this, FUNCTION_NAME);
#else
#define TRACE_FUNCTION
#endif
int c,d;
#define TRACE_CTOR TRACE_FUNCTION ++c
#define TRACE_DTOR TRACE_FUNCTION ++d
int throw_at = 0;
struct A {
A() { int i = c+1; if (i == throw_at) throw i; TRACE_CTOR; }
A(int i) { if (i == throw_at) throw i; TRACE_CTOR; }
A(const A&) { throw 10; }
A &operator=(const A&) { throw 11; return *this; }
~A() { TRACE_DTOR; }
};
int fails;
void try_idx (int i)
{
#if DEBUG
printf ("trying %d\n", i);
#endif
throw_at = i;
c = d = 0;
int t = 10;
try {
struct X {
A e1[2], e2;
}
x2[3] = { { 1, 2, 3 }, { 4, 5, 6 } };
} catch (int x) { t = x; }
if (t != i || c != d || c != i-1)
{
#if DEBUG
printf ("%d FAIL\n", i);
#endif
++fails;
}
}
int main()
{
for (int i = 1; i <= 10; ++i)
try_idx (i);
return fails;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment