re PR c++/27115 (ICE in cp_expr_size or miscompilation with statement expressions and constructors (and ?: ))
PR c++/27115 * gimplify.c (voidify_wrapper_expr): Handle STATEMENT_LIST as a wrapper. Loop to handle nested wrappers. (gimplify_bind_expr): Remove temp parameter. (gimplify_modify_expr_rhs): Handle CLEANUP_POINT_EXPR, BIND_EXPR and STATEMENT_LIST on the rhs. (gimplify_statement_list): Voidify the STATEMENT_LIST. (gimplify_expr): Pass pre_p to gimplify_statement_list. (gimplify_target_expr): Remove special BIND_EXPR handling. * cp/semantics.c (finish_stmt_expr_expr): Don't try to voidify here, just leave the expression as it is. (finish_stmt_expr): If the statement-expression has class type, wrap it in a TARGET_EXPR. * cp/cp-gimplify.c (cp_gimplify_init_expr): Don't bother with CLEANUP_POINT_EXPR. * cp/except.c (build_throw): Give the CLEANUP_POINT_EXPR void type. From-SVN: r116311
This commit is contained in:
parent
63b263936e
commit
c6c7698dfd
|
@ -1,3 +1,15 @@
|
|||
2006-08-21 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/27115
|
||||
* gimplify.c (voidify_wrapper_expr): Handle STATEMENT_LIST as a
|
||||
wrapper. Loop to handle nested wrappers.
|
||||
(gimplify_bind_expr): Remove temp parameter.
|
||||
(gimplify_modify_expr_rhs): Handle CLEANUP_POINT_EXPR, BIND_EXPR
|
||||
and STATEMENT_LIST on the rhs.
|
||||
(gimplify_statement_list): Voidify the STATEMENT_LIST.
|
||||
(gimplify_expr): Pass pre_p to gimplify_statement_list.
|
||||
(gimplify_target_expr): Remove special BIND_EXPR handling.
|
||||
|
||||
2006-08-21 J"orn Rennecke <joern.rennecke@st.com>
|
||||
|
||||
* config/sh/lib1funcs-Os-4-200.asm: Guard entire file with
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
2006-08-21 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/27115
|
||||
* semantics.c (finish_stmt_expr_expr): Don't try to voidify here,
|
||||
just leave the expression as it is.
|
||||
(finish_stmt_expr): If the statement-expression has class type,
|
||||
wrap it in a TARGET_EXPR.
|
||||
* cp-gimplify.c (cp_gimplify_init_expr): Don't bother with
|
||||
CLEANUP_POINT_EXPR.
|
||||
* except.c (build_throw): Give the CLEANUP_POINT_EXPR void type.
|
||||
|
||||
2006-08-21 Lee Millward <lee.millward@codesourcery.com>
|
||||
|
||||
PR c++/26269
|
||||
* decl.c (duplicate_decls): Return early if either
|
||||
newdecl or olddecl is error_mark_node.
|
||||
* decl.c (duplicate_decls): Return early if either
|
||||
newdecl or olddecl is error_mark_node.
|
||||
|
||||
PR c++/28505
|
||||
* decl.c (grokdeclarator): Return early after
|
||||
issuing diagnostic about an incomplete type.
|
||||
* decl.c (grokdeclarator): Return early after
|
||||
issuing diagnostic about an incomplete type.
|
||||
|
||||
PR c++/28741
|
||||
* tree.c (decl_anon_ns_mem_p): Robustify.
|
||||
* decl2.c (determine_visibility): Likewise.
|
||||
* tree.c (decl_anon_ns_mem_p): Robustify.
|
||||
* decl2.c (determine_visibility): Likewise.
|
||||
|
||||
2006-08-20 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
|
@ -189,18 +200,18 @@
|
|||
|
||||
2006-07-28 Lee Millward <lee.millward@codesourcery.com>
|
||||
|
||||
PR c++/27668
|
||||
PR c++/27962
|
||||
* pt.c (process_template_parm) Store invalid template
|
||||
parameters as error_mark_node in the paramater list.
|
||||
(push_inline_template_parms_recursive): Handle invalid
|
||||
template parameters.
|
||||
(comp_template_parms): Likewise.
|
||||
(check_default_tmpl_arg): Likewise.
|
||||
(coerce_template_template_parms): Likewise.
|
||||
(mangle_class_name_for_template): Likewise.
|
||||
(tsubst_template_parms): Likewise.
|
||||
* error.c (dump_template_argument_list): Likewise.
|
||||
PR c++/27668
|
||||
PR c++/27962
|
||||
* pt.c (process_template_parm) Store invalid template
|
||||
parameters as error_mark_node in the paramater list.
|
||||
(push_inline_template_parms_recursive): Handle invalid
|
||||
template parameters.
|
||||
(comp_template_parms): Likewise.
|
||||
(check_default_tmpl_arg): Likewise.
|
||||
(coerce_template_template_parms): Likewise.
|
||||
(mangle_class_name_for_template): Likewise.
|
||||
(tsubst_template_parms): Likewise.
|
||||
* error.c (dump_template_argument_list): Likewise.
|
||||
|
||||
2006-07-28 Kazu Hirata <kazu@codesourcery.com>
|
||||
|
||||
|
|
|
@ -391,18 +391,15 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
|||
tree to = TREE_OPERAND (*expr_p, 0);
|
||||
tree sub;
|
||||
|
||||
/* If we are initializing something from a TARGET_EXPR, strip the
|
||||
TARGET_EXPR and initialize it directly. */
|
||||
/* What about code that pulls out the temp and uses it elsewhere? I
|
||||
think that such code never uses the TARGET_EXPR as an initializer. If
|
||||
I'm wrong, we'll abort because the temp won't have any RTL. In that
|
||||
case, I guess we'll need to replace references somehow. */
|
||||
if (TREE_CODE (from) == TARGET_EXPR)
|
||||
from = TARGET_EXPR_INITIAL (from);
|
||||
if (TREE_CODE (from) == CLEANUP_POINT_EXPR)
|
||||
from = TREE_OPERAND (from, 0);
|
||||
|
||||
/* Look through any COMPOUND_EXPRs. */
|
||||
/* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them
|
||||
inside the TARGET_EXPR. */
|
||||
sub = expr_last (from);
|
||||
|
||||
/* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
|
||||
|
|
|
@ -744,7 +744,7 @@ build_throw (tree exp)
|
|||
/* Wrap the initialization in a CLEANUP_POINT_EXPR so that cleanups
|
||||
for temporaries within the initialization are run before the one
|
||||
for the exception object, preserving LIFO order. */
|
||||
exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
|
||||
exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp);
|
||||
|
||||
if (elided)
|
||||
exp = build2 (TRY_CATCH_EXPR, void_type_node, exp,
|
||||
|
|
|
@ -1612,70 +1612,46 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
|
|||
of the last statement is the value of the entire expression. */
|
||||
if (expr)
|
||||
{
|
||||
tree type;
|
||||
type = TREE_TYPE (expr);
|
||||
if (!dependent_type_p (type) && !VOID_TYPE_P (type))
|
||||
tree type = TREE_TYPE (expr);
|
||||
|
||||
if (processing_template_decl)
|
||||
{
|
||||
expr = decay_conversion (expr);
|
||||
expr = build_stmt (EXPR_STMT, expr);
|
||||
expr = add_stmt (expr);
|
||||
/* Mark the last statement so that we can recognize it as such at
|
||||
template-instantiation time. */
|
||||
EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
|
||||
}
|
||||
else if (VOID_TYPE_P (type))
|
||||
{
|
||||
/* Just treat this like an ordinary statement. */
|
||||
expr = finish_expr_stmt (expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It actually has a value we need to deal with. First, force it
|
||||
to be an rvalue so that we won't need to build up a copy
|
||||
constructor call later when we try to assign it to something. */
|
||||
expr = force_rvalue (expr);
|
||||
if (error_operand_p (expr))
|
||||
return error_mark_node;
|
||||
|
||||
/* Update for array-to-pointer decay. */
|
||||
type = TREE_TYPE (expr);
|
||||
|
||||
/* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a
|
||||
normal statement, but don't convert to void or actually add
|
||||
the EXPR_STMT. */
|
||||
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
|
||||
expr = maybe_cleanup_point_expr (expr);
|
||||
add_stmt (expr);
|
||||
}
|
||||
|
||||
/* The type of the statement-expression is the type of the last
|
||||
expression. */
|
||||
TREE_TYPE (stmt_expr) = type;
|
||||
/* We must take particular care if TYPE is a class type. In
|
||||
particular if EXPR creates a temporary of class type, then it
|
||||
must be destroyed at the semicolon terminating the last
|
||||
statement -- but we must make a copy before that happens.
|
||||
|
||||
This problem is solved by using a TARGET_EXPR to initialize a
|
||||
new temporary variable. The TARGET_EXPR itself is placed
|
||||
outside the statement-expression. However, the last
|
||||
statement in the statement-expression is transformed from
|
||||
EXPR to (approximately) T = EXPR, where T is the new
|
||||
temporary variable. Thus, the lifetime of the new temporary
|
||||
extends to the full-expression surrounding the
|
||||
statement-expression. */
|
||||
if (!processing_template_decl && !VOID_TYPE_P (type))
|
||||
{
|
||||
tree target_expr;
|
||||
if (CLASS_TYPE_P (type)
|
||||
&& !TYPE_HAS_TRIVIAL_INIT_REF (type))
|
||||
{
|
||||
target_expr = build_target_expr_with_type (expr, type);
|
||||
expr = TARGET_EXPR_INITIAL (target_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normally, build_target_expr will not create a
|
||||
TARGET_EXPR for scalars. However, we need the
|
||||
temporary here, in order to solve the scoping
|
||||
problem described above. */
|
||||
target_expr = force_target_expr (type, expr);
|
||||
expr = TARGET_EXPR_INITIAL (target_expr);
|
||||
expr = build2 (INIT_EXPR,
|
||||
type,
|
||||
TARGET_EXPR_SLOT (target_expr),
|
||||
expr);
|
||||
}
|
||||
TARGET_EXPR_INITIAL (target_expr) = NULL_TREE;
|
||||
/* Save away the TARGET_EXPR in the TREE_TYPE field of the
|
||||
STATEMENT_EXPR. We will retrieve it in
|
||||
finish_stmt_expr. */
|
||||
TREE_TYPE (stmt_expr) = target_expr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Having modified EXPR to reflect the extra initialization, we now
|
||||
treat it just like an ordinary statement. */
|
||||
expr = finish_expr_stmt (expr);
|
||||
|
||||
/* Mark the last statement so that we can recognize it as such at
|
||||
template-instantiation time. */
|
||||
if (expr && processing_template_decl)
|
||||
EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
|
||||
|
||||
return stmt_expr;
|
||||
}
|
||||
|
||||
|
@ -1696,6 +1672,7 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
|
|||
|
||||
type = TREE_TYPE (stmt_expr);
|
||||
result = pop_stmt_list (stmt_expr);
|
||||
TREE_TYPE (result) = type;
|
||||
|
||||
if (processing_template_decl)
|
||||
{
|
||||
|
@ -1703,12 +1680,13 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
|
|||
TREE_SIDE_EFFECTS (result) = 1;
|
||||
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
|
||||
}
|
||||
else if (!TYPE_P (type))
|
||||
else if (CLASS_TYPE_P (type))
|
||||
{
|
||||
gcc_assert (TREE_CODE (type) == TARGET_EXPR);
|
||||
TARGET_EXPR_INITIAL (type) = result;
|
||||
TREE_TYPE (result) = void_type_node;
|
||||
result = type;
|
||||
/* Wrap the statement-expression in a TARGET_EXPR so that the
|
||||
temporary object created by the final expression is destroyed at
|
||||
the end of the full-expression containing the
|
||||
statement-expression. */
|
||||
result = force_target_expr (type, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
146
gcc/gimplify.c
146
gcc/gimplify.c
|
@ -957,71 +957,71 @@ voidify_wrapper_expr (tree wrapper, tree temp)
|
|||
{
|
||||
if (!VOID_TYPE_P (TREE_TYPE (wrapper)))
|
||||
{
|
||||
tree *p, sub = wrapper;
|
||||
tree type = TREE_TYPE (wrapper);
|
||||
tree *p;
|
||||
|
||||
restart:
|
||||
/* Set p to point to the body of the wrapper. */
|
||||
switch (TREE_CODE (sub))
|
||||
/* Set p to point to the body of the wrapper. Loop until we find
|
||||
something that isn't a wrapper. */
|
||||
for (p = &wrapper; p && *p; )
|
||||
{
|
||||
case BIND_EXPR:
|
||||
/* For a BIND_EXPR, the body is operand 1. */
|
||||
p = &BIND_EXPR_BODY (sub);
|
||||
break;
|
||||
|
||||
default:
|
||||
p = &TREE_OPERAND (sub, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance to the last statement. Set all container types to void. */
|
||||
if (TREE_CODE (*p) == STATEMENT_LIST)
|
||||
{
|
||||
tree_stmt_iterator i = tsi_last (*p);
|
||||
p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
|
||||
switch (TREE_CODE (*p))
|
||||
{
|
||||
case BIND_EXPR:
|
||||
TREE_SIDE_EFFECTS (*p) = 1;
|
||||
TREE_TYPE (*p) = void_type_node;
|
||||
/* For a BIND_EXPR, the body is operand 1. */
|
||||
p = &BIND_EXPR_BODY (*p);
|
||||
break;
|
||||
|
||||
case CLEANUP_POINT_EXPR:
|
||||
case TRY_FINALLY_EXPR:
|
||||
case TRY_CATCH_EXPR:
|
||||
TREE_SIDE_EFFECTS (*p) = 1;
|
||||
TREE_TYPE (*p) = void_type_node;
|
||||
p = &TREE_OPERAND (*p, 0);
|
||||
break;
|
||||
|
||||
case STATEMENT_LIST:
|
||||
{
|
||||
tree_stmt_iterator i = tsi_last (*p);
|
||||
TREE_SIDE_EFFECTS (*p) = 1;
|
||||
TREE_TYPE (*p) = void_type_node;
|
||||
p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
|
||||
}
|
||||
break;
|
||||
|
||||
case COMPOUND_EXPR:
|
||||
/* Advance to the last statement. Set all container types to void. */
|
||||
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
|
||||
{
|
||||
TREE_SIDE_EFFECTS (*p) = 1;
|
||||
TREE_TYPE (*p) = void_type_node;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (p == NULL || IS_EMPTY_STMT (*p))
|
||||
;
|
||||
/* Look through exception handling. */
|
||||
else if (TREE_CODE (*p) == TRY_FINALLY_EXPR
|
||||
|| TREE_CODE (*p) == TRY_CATCH_EXPR)
|
||||
temp = NULL_TREE;
|
||||
else if (temp)
|
||||
{
|
||||
sub = *p;
|
||||
goto restart;
|
||||
}
|
||||
/* The C++ frontend already did this for us. */
|
||||
else if (TREE_CODE (*p) == INIT_EXPR
|
||||
|| TREE_CODE (*p) == TARGET_EXPR)
|
||||
temp = TREE_OPERAND (*p, 0);
|
||||
/* If we're returning a dereference, move the dereference
|
||||
outside the wrapper. */
|
||||
else if (TREE_CODE (*p) == INDIRECT_REF)
|
||||
{
|
||||
tree ptr = TREE_OPERAND (*p, 0);
|
||||
temp = create_tmp_var (TREE_TYPE (ptr), "retval");
|
||||
*p = build2 (MODIFY_EXPR, TREE_TYPE (ptr), temp, ptr);
|
||||
temp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (temp)), temp);
|
||||
/* If this is a BIND_EXPR for a const inline function, it might not
|
||||
have TREE_SIDE_EFFECTS set. That is no longer accurate. */
|
||||
TREE_SIDE_EFFECTS (wrapper) = 1;
|
||||
/* The wrapper is on the RHS of an assignment that we're pushing
|
||||
down. */
|
||||
gcc_assert (TREE_CODE (temp) == INIT_EXPR
|
||||
|| TREE_CODE (temp) == MODIFY_EXPR);
|
||||
TREE_OPERAND (temp, 1) = *p;
|
||||
*p = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!temp)
|
||||
temp = create_tmp_var (TREE_TYPE (wrapper), "retval");
|
||||
*p = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, *p);
|
||||
TREE_SIDE_EFFECTS (wrapper) = 1;
|
||||
temp = create_tmp_var (type, "retval");
|
||||
*p = build2 (INIT_EXPR, type, temp, *p);
|
||||
}
|
||||
|
||||
TREE_TYPE (wrapper) = void_type_node;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
@ -1050,13 +1050,13 @@ build_stack_save_restore (tree *save, tree *restore)
|
|||
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
|
||||
gimplify_bind_expr (tree *expr_p, tree *pre_p)
|
||||
{
|
||||
tree bind_expr = *expr_p;
|
||||
bool old_save_stack = gimplify_ctxp->save_stack;
|
||||
tree t;
|
||||
|
||||
temp = voidify_wrapper_expr (bind_expr, temp);
|
||||
tree temp = voidify_wrapper_expr (bind_expr, NULL);
|
||||
|
||||
/* Mark variables seen in this bind expr. */
|
||||
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
|
||||
|
@ -3408,6 +3408,20 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
|
|||
ret = GS_UNHANDLED;
|
||||
break;
|
||||
|
||||
/* If we're initializing from a container, push the initialization
|
||||
inside it. */
|
||||
case CLEANUP_POINT_EXPR:
|
||||
case BIND_EXPR:
|
||||
case STATEMENT_LIST:
|
||||
{
|
||||
tree wrap = *from_p;
|
||||
tree t = voidify_wrapper_expr (wrap, *expr_p);
|
||||
gcc_assert (t == *expr_p);
|
||||
|
||||
*expr_p = wrap;
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = GS_UNHANDLED;
|
||||
break;
|
||||
|
@ -3681,8 +3695,10 @@ gimplify_compound_expr (tree *expr_p, tree *pre_p, bool want_value)
|
|||
enlightened front-end, or by shortcut_cond_expr. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_statement_list (tree *expr_p)
|
||||
gimplify_statement_list (tree *expr_p, tree *pre_p)
|
||||
{
|
||||
tree temp = voidify_wrapper_expr (*expr_p, NULL);
|
||||
|
||||
tree_stmt_iterator i = tsi_start (*expr_p);
|
||||
|
||||
while (!tsi_end_p (i))
|
||||
|
@ -3703,6 +3719,13 @@ gimplify_statement_list (tree *expr_p)
|
|||
tsi_next (&i);
|
||||
}
|
||||
|
||||
if (temp)
|
||||
{
|
||||
append_to_statement_list (*expr_p, pre_p);
|
||||
*expr_p = temp;
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
return GS_ALL_DONE;
|
||||
}
|
||||
|
||||
|
@ -4184,16 +4207,9 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
|||
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
|
||||
else
|
||||
{
|
||||
/* Special handling for BIND_EXPR can result in fewer temps. */
|
||||
ret = GS_OK;
|
||||
if (TREE_CODE (init) == BIND_EXPR)
|
||||
gimplify_bind_expr (&init, temp, pre_p);
|
||||
if (init != temp)
|
||||
{
|
||||
init = build2 (INIT_EXPR, void_type_node, temp, init);
|
||||
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
|
||||
fb_none);
|
||||
}
|
||||
init = build2 (INIT_EXPR, void_type_node, temp, init);
|
||||
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
|
||||
fb_none);
|
||||
}
|
||||
if (ret == GS_ERROR)
|
||||
return GS_ERROR;
|
||||
|
@ -5507,7 +5523,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
|
|||
break;
|
||||
|
||||
case BIND_EXPR:
|
||||
ret = gimplify_bind_expr (expr_p, NULL, pre_p);
|
||||
ret = gimplify_bind_expr (expr_p, pre_p);
|
||||
break;
|
||||
|
||||
case LOOP_EXPR:
|
||||
|
@ -5654,7 +5670,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
|
|||
break;
|
||||
|
||||
case STATEMENT_LIST:
|
||||
ret = gimplify_statement_list (expr_p);
|
||||
ret = gimplify_statement_list (expr_p, pre_p);
|
||||
break;
|
||||
|
||||
case WITH_SIZE_EXPR:
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Test for "sticky cancel": if a catch (...) block discards the
|
||||
// cancellation exception, a new one is raised at the next cancellation
|
||||
// point.
|
||||
|
||||
// This test only applies to glibc targets.
|
||||
// { dg-do run { target *-*-linux* } }
|
||||
// { dg-options "-pthread" }
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cxxabi.h>
|
||||
extern "C" int printf (const char *, ...);
|
||||
|
||||
void* thread_main(void*)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Spin until we get cancelled.
|
||||
while (1)
|
||||
pthread_testcancel();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Catch and discard the forced unwind.
|
||||
printf ("caught ...\n");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Start unwinding again.
|
||||
pthread_testcancel();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Catch and discard again. This time the thread exits before the
|
||||
// next cancellation point, so we're done.
|
||||
printf ("caught ... again\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (void*)4;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t thread;
|
||||
int r;
|
||||
void *p;
|
||||
|
||||
r = pthread_create (&thread, NULL, thread_main, NULL);
|
||||
if (r)
|
||||
return 1;
|
||||
|
||||
r = pthread_cancel (thread);
|
||||
if (r)
|
||||
return 2;
|
||||
|
||||
r = pthread_join (thread, &p);
|
||||
if (r)
|
||||
return 3;
|
||||
|
||||
return (int)p;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// This test only applies to glibc (NPTL) targets.
|
||||
// { dg-do run { target *-*-linux* } }
|
||||
// { dg-options "-pthread" }
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cxxabi.h>
|
||||
extern "C" int printf (const char *, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
pthread_exit (0);
|
||||
}
|
||||
catch (abi::__forced_unwind &)
|
||||
{
|
||||
printf ("caught forced unwind\n");
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf ("caught ...\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// PR c++/27115
|
||||
|
||||
// { dg-do run }
|
||||
// { dg-options "" }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
A (int j) : i(j) {}
|
||||
A (const A &j) : i(j.i) {}
|
||||
A& operator= (const A &j) { i = j.i; return *this; }
|
||||
};
|
||||
|
||||
A foo(int j)
|
||||
{
|
||||
return ({ j ? A(1) : A(0); });
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return foo(1).i-1;
|
||||
}
|
||||
|
||||
void foo2()
|
||||
{
|
||||
A b = ({ A a(1); a; });
|
||||
}
|
||||
|
Loading…
Reference in New Issue