From c3d09d4da1e9d3d59cf01acc2c4e52c6c764f383 Mon Sep 17 00:00:00 2001
From: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 21 Aug 2006 20:54:57 +0000
Subject: [PATCH]         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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@116311 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                            |  12 ++
 gcc/cp/ChangeLog                         |  47 +++++---
 gcc/cp/cp-gimplify.c                     |   7 +-
 gcc/cp/except.c                          |   2 +-
 gcc/cp/semantics.c                       |  96 ++++++---------
 gcc/gimplify.c                           | 146 +++++++++++++----------
 gcc/testsuite/g++.dg/abi/forced-sticky.C |  62 ++++++++++
 gcc/testsuite/g++.dg/abi/forced.C        |  25 ++++
 gcc/testsuite/g++.dg/ext/stmtexpr8.C     |  28 +++++
 9 files changed, 277 insertions(+), 148 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/abi/forced-sticky.C
 create mode 100644 gcc/testsuite/g++.dg/abi/forced.C
 create mode 100644 gcc/testsuite/g++.dg/ext/stmtexpr8.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dc3fef912f15..685b4b6daf9a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 758f877187fe..fa7d6bc0e65b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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>
 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index ca8ff5fcfdee..bdb2edf2f416 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -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
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 17166d92af0d..71b433f15603 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -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,
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fb4ea0a79dfa..56dbe6fddad6 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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 = 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))
 	{
-	  expr = decay_conversion (expr);
+	  /* 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;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 6ade10cca299..fd9e1e561572 100644
--- a/gcc/gimplify.c
+++ b/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))
-	{
-	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
+      /* 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; )
 	{
-	  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:
diff --git a/gcc/testsuite/g++.dg/abi/forced-sticky.C b/gcc/testsuite/g++.dg/abi/forced-sticky.C
new file mode 100644
index 000000000000..0d31ee435471
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/forced-sticky.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/abi/forced.C b/gcc/testsuite/g++.dg/abi/forced.C
new file mode 100644
index 000000000000..7a9c35964f7c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/forced.C
@@ -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;
+    }
+}
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr8.C b/gcc/testsuite/g++.dg/ext/stmtexpr8.C
new file mode 100644
index 000000000000..8e5d0ddcba25
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr8.C
@@ -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; });
+}
+
-- 
GitLab