aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hongjiu.lu@intel.com>2008-08-13 18:35:31 +0000
committerH.J. Lu <hongjiu.lu@intel.com>2008-08-13 18:35:31 +0000
commit66c302abe513b7c3c2d711827564c30e5cedb624 (patch)
treed5cbc9d3a8b9b7319f01197ce943d6d8cef81f2a
parent596835d282b25c2ab724c47db5694f0b05090031 (diff)
Merged with trunk at revision 139065.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/stack@139066 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog51
-rw-r--r--gcc/c-common.c17
-rw-r--r--gcc/c-common.h5
-rw-r--r--gcc/c-decl.c43
-rw-r--r--gcc/c-opts.c30
-rw-r--r--gcc/c.opt2
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/decl.c3
-rw-r--r--gcc/doc/invoke.texi9
-rw-r--r--gcc/dwarf2out.c73
-rw-r--r--gcc/expr.c31
-rw-r--r--gcc/gimplify.c36
-rw-r--r--gcc/testsuite/ChangeLog19
-rw-r--r--gcc/testsuite/g++.dg/warn/pr30551-2.C6
-rw-r--r--gcc/testsuite/g++.dg/warn/pr30551.C6
-rw-r--r--gcc/testsuite/gcc.dg/pr30551-2.c8
-rw-r--r--gcc/testsuite/gcc.dg/pr30551-3.c7
-rw-r--r--gcc/testsuite/gcc.dg/pr30551-4.c8
-rw-r--r--gcc/testsuite/gcc.dg/pr30551-5.c7
-rw-r--r--gcc/testsuite/gcc.dg/pr30551-6.c7
-rw-r--r--gcc/testsuite/gcc.dg/pr30551.c7
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/reassoc-3.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c25
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c15
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c19
-rw-r--r--gcc/tree-ssa-ccp.c134
-rw-r--r--gcc/tree.h1
-rw-r--r--libstdc++-v3/ChangeLog35
-rw-r--r--libstdc++-v3/config/abi/pre/gnu.ver29
-rw-r--r--libstdc++-v3/libsupc++/Makefile.am3
-rw-r--r--libstdc++-v3/libsupc++/Makefile.in9
-rw-r--r--libstdc++-v3/libsupc++/eh_alloc.cc68
-rw-r--r--libstdc++-v3/libsupc++/eh_arm.cc8
-rw-r--r--libstdc++-v3/libsupc++/eh_call.cc4
-rw-r--r--libstdc++-v3/libsupc++/eh_personality.cc22
-rw-r--r--libstdc++-v3/libsupc++/eh_ptr.cc236
-rw-r--r--libstdc++-v3/libsupc++/eh_throw.cc21
-rw-r--r--libstdc++-v3/libsupc++/eh_type.cc12
-rw-r--r--libstdc++-v3/libsupc++/exception7
-rw-r--r--libstdc++-v3/libsupc++/exception_ptr.h169
-rw-r--r--libstdc++-v3/libsupc++/unwind-cxx.h142
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc90
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc188
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/rethrow_exception.cc113
44 files changed, 1516 insertions, 216 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f07113a13e2..ad4b63bc675 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,54 @@
+2008-08-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ * dwarf2out.c (dwarf_stack_op_name): Remove prototype.
+ (new_loc_descr): Likewise.
+ (add_loc_descr): Likewise.
+ (size_of_loc_descr): Likewise.
+ (size_of_locs): Likewise.
+ (output_loc_operands): Likewise.
+ (output_loc_sequence): Likewise.
+ (new_reg_loc_descr): New.
+ (build_cfa_loc): Use it.
+ (build_cfa_aligned_loc): Likewise.
+ (one_reg_loc_descriptor): Likewise.
+ (based_loc_descr): Likewise.
+
+2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
+
+ PR 30551
+ * doc/invoke.texi (Wmain): Update.
+ * c-decl.c (start_decl): warn_main is only 0 or 1.
+ (start_function): Likewise. Fix formatting.
+ (finish_function): Delete redundant warning.
+ * c.opt (Wmain): Add Var(warn_main) and Init(-1).
+ * c-opts (c_common_handle_option): -Wall only has effect if
+ warn_main is uninitialized. OPT_Wmain is automatically
+ handled. -pedantic also enables Wmain.
+ (c_common_post_options): Handle all logic for Wmain here.
+ * c-common.c (warn_main): Delete.
+ (check_main_parameter_types): Make pedwarns conditional on
+ OPT_Wmain.
+ * c-common.h (warn_main): Delete.
+
+2008-08-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR middle-end/36701
+ * expr.c (emit_group_store): Allocate stack temp with the
+ largest alignment when copying from register to stack.
+
+2008-08-13 Richard Guenther <rguenther@suse.de>
+
+ * tree.h (maybe_fold_offset_to_address): Declare.
+ * tree-ssa-ccp.c (surely_varying_stmt_p): Fix typo in last commit.
+ (ccp_fold): Handle pointer conversions the same as fold_stmt.
+ Likewise for POINTER_PLUS_EXPR.
+ (maybe_fold_offset_to_reference): Enable disabled code.
+ (maybe_fold_offset_to_address): New function.
+ (fold_stmt_r): Use it.
+ (fold_gimple_assign): Likewise.
+ * gimplify.c (gimplify_conversion): Use maybe_fold_offset_to_address.
+ (gimplify_expr): Likewise.
+
2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
* toplev.h (pedwarn_at): Fix declaration.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 93021820cd6..8bac9cb4f03 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -342,10 +342,6 @@ int flag_isoc99;
int flag_hosted = 1;
-/* Warn if main is suspicious. */
-
-int warn_main;
-
/* ObjC language option variables. */
@@ -1363,7 +1359,8 @@ check_main_parameter_types (tree decl)
{
case 1:
if (TYPE_MAIN_VARIANT (type) != integer_type_node)
- pedwarn (0, "first argument of %q+D should be %<int%>", decl);
+ pedwarn (OPT_Wmain, "first argument of %q+D should be %<int%>",
+ decl);
break;
case 2:
@@ -1371,8 +1368,8 @@ check_main_parameter_types (tree decl)
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
!= char_type_node))
- pedwarn (0, "second argument of %q+D should be %<char **%>",
- decl);
+ pedwarn (OPT_Wmain, "second argument of %q+D should be %<char **%>",
+ decl);
break;
case 3:
@@ -1380,8 +1377,8 @@ check_main_parameter_types (tree decl)
|| TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
!= char_type_node))
- pedwarn (0, "third argument of %q+D should probably be "
- "%<char **%>", decl);
+ pedwarn (OPT_Wmain, "third argument of %q+D should probably be "
+ "%<char **%>", decl);
break;
}
}
@@ -1390,7 +1387,7 @@ check_main_parameter_types (tree decl)
argument because it's only mentioned in an appendix of the
standard. */
if (argct > 0 && (argct < 2 || argct > 3))
- pedwarn (0, "%q+D takes only zero or two arguments", decl);
+ pedwarn (OPT_Wmain, "%q+D takes only zero or two arguments", decl);
}
/* True if pointers to distinct types T1 and T2 can be converted to
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 0f2a359c16f..b0abe3e1a51 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -498,11 +498,6 @@ extern int flag_isoc99;
extern int flag_hosted;
-/* Warn if main is suspicious. */
-
-extern int warn_main;
-
-
/* ObjC language option variables. */
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index e55e809b1f4..7be2ca4e60a 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -3153,8 +3153,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
if (!decl)
return 0;
- if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL
- && MAIN_NAME_P (DECL_NAME (decl)))
+ if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
if (initialized)
@@ -6207,13 +6206,13 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
maybe_apply_pragma_weak (decl1);
/* Warn for unlikely, improbable, or stupid declarations of `main'. */
- if (warn_main > 0 && MAIN_NAME_P (DECL_NAME (decl1)))
+ if (warn_main && MAIN_NAME_P (DECL_NAME (decl1)))
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
!= integer_type_node)
pedwarn (OPT_Wmain, "return type of %q+D is not %<int%>", decl1);
- check_main_parameter_types(decl1);
+ check_main_parameter_types (decl1);
if (!TREE_PUBLIC (decl1))
pedwarn (OPT_Wmain, "%q+D is normally a non-static function", decl1);
@@ -6672,30 +6671,18 @@ finish_function (void)
if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node)
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
- if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted)
- {
- if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
- != integer_type_node)
- {
- /* If warn_main is 1 (-Wmain) or 2 (-Wall), we have already warned.
- If warn_main is -1 (-Wno-main) we don't want to be warned. */
- if (!warn_main)
- pedwarn (0, "return type of %q+D is not %<int%>", fndecl);
- }
- else
- {
- if (flag_isoc99)
- {
- tree stmt = c_finish_return (integer_zero_node);
- /* Hack. We don't want the middle-end to warn that this return
- is unreachable, so we mark its location as special. Using
- UNKNOWN_LOCATION has the problem that it gets clobbered in
- annotate_one_with_locus. A cleaner solution might be to
- ensure ! should_carry_locus_p (stmt), but that needs a flag.
- */
- SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION);
- }
- }
+ if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted
+ && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
+ == integer_type_node && flag_isoc99)
+ {
+ tree stmt = c_finish_return (integer_zero_node);
+ /* Hack. We don't want the middle-end to warn that this return
+ is unreachable, so we mark its location as special. Using
+ UNKNOWN_LOCATION has the problem that it gets clobbered in
+ annotate_one_with_locus. A cleaner solution might be to
+ ensure ! should_carry_locus_p (stmt), but that needs a flag.
+ */
+ SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION);
}
/* Tie off the statement tree for this function. */
diff --git a/gcc/c-opts.c b/gcc/c-opts.c
index 83e2ed14c4e..300bf14f503 100644
--- a/gcc/c-opts.c
+++ b/gcc/c-opts.c
@@ -404,9 +404,12 @@ c_common_handle_option (size_t scode, const char *arg, int value)
warn_uninitialized = (value ? 2 : 0);
if (!c_dialect_cxx ())
- /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding
- can turn it off only if it's not explicit. */
- warn_main = value * 2;
+ {
+ /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding
+ can turn it off only if it's not explicit. */
+ if (warn_main == -1)
+ warn_main = (value ? 2 : 0);
+ }
else
{
/* C++-specific warnings. */
@@ -467,13 +470,6 @@ c_common_handle_option (size_t scode, const char *arg, int value)
cpp_opts->warn_invalid_pch = value;
break;
- case OPT_Wmain:
- if (value)
- warn_main = 1;
- else
- warn_main = -1;
- break;
-
case OPT_Wmissing_include_dirs:
cpp_opts->warn_missing_include_dirs = value;
break;
@@ -615,9 +611,6 @@ c_common_handle_option (size_t scode, const char *arg, int value)
case OPT_fhosted:
flag_hosted = value;
flag_no_builtin = !value;
- /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */
- if (!value && warn_main == 2)
- warn_main = 0;
break;
case OPT_fshort_double:
@@ -907,6 +900,8 @@ c_common_handle_option (size_t scode, const char *arg, int value)
warn_pointer_sign = 1;
if (warn_overlength_strings == -1)
warn_overlength_strings = 1;
+ if (warn_main == -1)
+ warn_main = 2;
break;
case OPT_print_objc_runtime_info:
@@ -1071,6 +1066,15 @@ c_common_post_options (const char **pfilename)
if (warn_overlength_strings == -1 || c_dialect_cxx ())
warn_overlength_strings = 0;
+ /* Wmain is enabled by default in C++ but not in C. */
+ /* Wmain is disabled by default for -ffreestanding (!flag_hosted),
+ even if -Wall was given (warn_main will be 2 if set by -Wall, 1
+ if set by -Wmain). */
+ if (warn_main == -1)
+ warn_main = (c_dialect_cxx () && flag_hosted) ? 1 : 0;
+ else if (warn_main == 2)
+ warn_main = flag_hosted ? 1 : 0;
+
/* In C, -Wconversion enables -Wsign-conversion (unless disabled
through -Wno-sign-conversion). While in C++,
-Wsign-conversion needs to be requested explicitly. */
diff --git a/gcc/c.opt b/gcc/c.opt
index 30782d4f3a7..d33fa46e8a7 100644
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -281,7 +281,7 @@ C ObjC C++ ObjC++ Var(warn_long_long) Init(1) Warning
Do not warn about using \"long long\" when -pedantic
Wmain
-C ObjC C++ ObjC++ Warning
+C ObjC C++ ObjC++ Var(warn_main) Init(-1) Warning
Warn about suspicious declarations of \"main\"
Wmissing-braces
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 00b3613802d..e34fb2270a9 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
+
+ PR 30551
+ * decl.c (grokfndecl): Call check_main_parameters_type only if
+ -Wmain.
+
2008-08-12 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/37087
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 691056252aa..3cd251128f1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6692,7 +6692,8 @@ grokfndecl (tree ctype,
newtype = build_function_type (integer_type_node, oldtypeargs);
TREE_TYPE (decl) = newtype;
}
- check_main_parameter_types (decl);
+ if (warn_main)
+ check_main_parameter_types (decl);
}
if (ctype != NULL_TREE
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 906c6a6dbc3..56a0bdadc55 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -2940,10 +2940,11 @@ This warning is also enabled by @option{-Wextra}.
@item -Wmain
@opindex Wmain
@opindex Wno-main
-Warn if the type of @samp{main} is suspicious. @samp{main} should be a
-function with external linkage, returning int, taking either zero
-arguments, two, or three arguments of appropriate types.
-This warning is enabled by @option{-Wall}.
+Warn if the type of @samp{main} is suspicious. @samp{main} should be
+a function with external linkage, returning int, taking either zero
+arguments, two, or three arguments of appropriate types. This warning
+is enabled by default in C++ and is enabled by either @option{-Wall}
+or @option{-pedantic}.
@item -Wmissing-braces
@opindex Wmissing-braces
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8cfbf38aa35..56b09e7fd86 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3472,15 +3472,7 @@ typedef struct dw_loc_list_struct GTY(())
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-static const char *dwarf_stack_op_name (unsigned);
-static dw_loc_descr_ref new_loc_descr (enum dwarf_location_atom,
- unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
-static void add_loc_descr (dw_loc_descr_ref *, dw_loc_descr_ref);
-static unsigned long size_of_loc_descr (dw_loc_descr_ref);
-static unsigned long size_of_locs (dw_loc_descr_ref);
-static void output_loc_operands (dw_loc_descr_ref);
-static void output_loc_sequence (dw_loc_descr_ref);
/* Convert a DWARF stack opcode into its string name. */
@@ -3816,6 +3808,25 @@ new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
return descr;
}
+/* Return a pointer to a newly allocated location description for
+ REG and OFFSET. */
+
+static inline dw_loc_descr_ref
+new_reg_loc_descr (unsigned int reg, unsigned HOST_WIDE_INT offset)
+{
+ if (offset)
+ {
+ if (reg <= 31)
+ return new_loc_descr (DW_OP_breg0 + reg, offset, 0);
+ else
+ return new_loc_descr (DW_OP_bregx, reg, offset);
+ }
+ else if (reg <= 31)
+ return new_loc_descr (DW_OP_reg0 + reg, 0, 0);
+ else
+ return new_loc_descr (DW_OP_regx, reg, 0);
+}
+
/* Add a location description term to a location description expression. */
static inline void
@@ -4316,18 +4327,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
if (cfa->indirect)
{
- if (cfa->base_offset)
- {
- if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
- else
- head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
- }
- else if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
- else
- head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
-
+ head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
head->dw_loc_oprnd1.val_class = dw_val_class_const;
tmp = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (&head, tmp);
@@ -4338,17 +4338,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
}
}
else
- {
- if (offset == 0)
- if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
- else
- head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
- else if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_breg0 + cfa->reg, offset, 0);
- else
- head = new_loc_descr (DW_OP_bregx, cfa->reg, offset);
- }
+ head = new_reg_loc_descr (cfa->reg, offset);
return head;
}
@@ -4367,21 +4357,15 @@ build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
/* When CFA is defined as FP+OFFSET, emulate stack alignment. */
if (cfa.reg == HARD_FRAME_POINTER_REGNUM && cfa.indirect == 0)
{
- if (dwarf_fp <= 31)
- head = new_loc_descr (DW_OP_breg0 + dwarf_fp, 0, 0);
- else
- head = new_loc_descr (DW_OP_bregx, dwarf_fp, 0);
-
+ head = new_reg_loc_descr (dwarf_fp, 0);
add_loc_descr (&head, int_loc_descriptor (alignment));
add_loc_descr (&head, new_loc_descr (DW_OP_and, 0, 0));
add_loc_descr (&head, int_loc_descriptor (offset));
add_loc_descr (&head, new_loc_descr (DW_OP_plus, 0, 0));
}
- else if (dwarf_fp <= 31)
- head = new_loc_descr (DW_OP_breg0 + dwarf_fp, offset, 0);
else
- head = new_loc_descr (DW_OP_bregx, dwarf_fp, offset);
+ head = new_reg_loc_descr (dwarf_fp, offset);
return head;
}
@@ -9663,11 +9647,7 @@ reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
static dw_loc_descr_ref
one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
{
- dw_loc_descr_ref reg_loc_descr;
- if (regno <= 31)
- reg_loc_descr = new_loc_descr (DW_OP_reg0 + regno, 0, 0);
- else
- reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+ dw_loc_descr_ref reg_loc_descr = new_reg_loc_descr (regno, 0);
if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
@@ -9830,10 +9810,7 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset,
= DWARF_FRAME_REGNUM (cfa.indirect
? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM);
- if (base_reg <= 31)
- return new_loc_descr (DW_OP_breg0 + base_reg, offset, 0);
- else
- return new_loc_descr (DW_OP_bregx, base_reg, offset);
+ return new_reg_loc_descr (base_reg, offset);
}
offset += frame_pointer_fb_offset;
diff --git a/gcc/expr.c b/gcc/expr.c
index e61dc616165..7cc8783e0bc 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2074,12 +2074,31 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
}
else
{
- gcc_assert (bytepos == 0 && XVECLEN (src, 0));
- dest = assign_stack_temp (GET_MODE (dest),
- GET_MODE_SIZE (GET_MODE (dest)), 0);
- emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
- tmps[i]);
- dst = dest;
+ enum machine_mode dest_mode = GET_MODE (dest);
+ enum machine_mode tmp_mode = GET_MODE (tmps[i]);
+ int dest_size = GET_MODE_SIZE (dest_mode);
+ int tmp_size = GET_MODE_SIZE (tmp_mode);
+
+ gcc_assert (bytepos == 0
+ && XVECLEN (src, 0)
+ && dest_size == tmp_size);
+
+ if (GET_MODE_ALIGNMENT (dest_mode)
+ >= GET_MODE_ALIGNMENT (tmp_mode))
+ {
+ dest = assign_stack_temp (dest_mode, dest_size, 0);
+ emit_move_insn (adjust_address (dest,
+ tmp_mode,
+ bytepos),
+ tmps[i]);
+ dst = dest;
+ }
+ else
+ {
+ dest = assign_stack_temp (tmp_mode, tmp_size, 0);
+ emit_move_insn (dest, tmps[i]);
+ dst = adjust_address (dest, dest_mode, bytepos);
+ }
break;
}
}
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 753aa591e40..43c8df991fc 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1842,17 +1842,13 @@ gimplify_conversion (tree *expr_p)
/* Attempt to avoid NOP_EXPR by producing reference to a subtype.
For example this fold (subclass *)&A into &A->subclass avoiding
a need for statement. */
- if (TREE_CODE (*expr_p) == NOP_EXPR
+ if (CONVERT_EXPR_P (*expr_p)
&& POINTER_TYPE_P (TREE_TYPE (*expr_p))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
- && (tem = maybe_fold_offset_to_reference
+ && (tem = maybe_fold_offset_to_address
(TREE_OPERAND (*expr_p, 0),
- integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p)))))
- {
- tree ptr_type = build_pointer_type (TREE_TYPE (tem));
- if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
- *expr_p = build_fold_addr_expr_with_type (tem, ptr_type);
- }
+ integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE)
+ *expr_p = tem;
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
@@ -6735,30 +6731,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
The second is gimple immediate saving a need for extra statement.
*/
if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
- && (tmp = maybe_fold_offset_to_reference
+ && (tmp = maybe_fold_offset_to_address
(TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
- TREE_TYPE (TREE_TYPE (*expr_p)))))
- {
- tree ptr_type = build_pointer_type (TREE_TYPE (tmp));
- if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
- {
- *expr_p = build_fold_addr_expr_with_type (tmp, ptr_type);
- break;
- }
- }
+ TREE_TYPE (*expr_p))))
+ {
+ *expr_p = tmp;
+ break;
+ }
/* Convert (void *)&a + 4 into (void *)&a[1]. */
if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
0),0)))
- && (tmp = maybe_fold_offset_to_reference
+ && (tmp = maybe_fold_offset_to_address
(TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
TREE_OPERAND (*expr_p, 1),
- TREE_TYPE (TREE_TYPE
- (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
- 0))))))
+ TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
+ 0)))))
{
- tmp = build_fold_addr_expr (tmp);
*expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
break;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d036b781439..1f1890a1435 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
+
+ PR 30551
+ * gcc.dg/pr30551.c: New.
+ * gcc.dg/pr30551-2.c: New.
+ * gcc.dg/pr30551-3.c: New.
+ * gcc.dg/pr30551-4.c: New.
+ * gcc.dg/pr30551-5.c: New.
+ * gcc.dg/pr30551-6.c: New.
+ * gcc.dg/tree-ssa/reassoc-3.c: Don't compile with -pedantic-errors.
+ * g++.dg/warn/pr30551.C: New.
+ * g++.dg/warn/pr30551-2.C: New.
+
+2008-08-13 Richard Guenther <rguenther@suse.de>
+
+ * gcc.dg/tree-ssa/ssa-ccp-21.c: New testcase.
+ * gcc.dg/tree-ssa/ssa-ccp-22.c: Likewise.
+ * gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.
+
2008-08-13 Samuel Tardieu <sam@rfc1149.net>
PR ada/36777
diff --git a/gcc/testsuite/g++.dg/warn/pr30551-2.C b/gcc/testsuite/g++.dg/warn/pr30551-2.C
new file mode 100644
index 00000000000..7a4b136579d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr30551-2.C
@@ -0,0 +1,6 @@
+// PR 30551 -Wmain is enabled by -pedantic/-pedantic-errors.
+// { dg-do compile }
+// { dg-options "-pedantic-errors" }
+
+int main(char a) {} /* { dg-error "error: first argument of .*main.* should be .int." } */
+/* { dg-error "error: .*main.* takes only zero or two arguments" "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/g++.dg/warn/pr30551.C b/gcc/testsuite/g++.dg/warn/pr30551.C
new file mode 100644
index 00000000000..ed9248744db
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr30551.C
@@ -0,0 +1,6 @@
+// PR 30551 -Wmain is enabled by default.
+// { dg-do compile }
+// { dg-options "" }
+
+int main(char a) {} /* { dg-warning "warning: first argument of .*main.* should be .int." } */
+/* { dg-warning "warning: .*main.* takes only zero or two arguments" "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/gcc.dg/pr30551-2.c b/gcc/testsuite/gcc.dg/pr30551-2.c
new file mode 100644
index 00000000000..fdd5df66868
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551-2.c
@@ -0,0 +1,8 @@
+/* PR 30551 -Wmain is not enabled by default. */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void main(char a) {} /* { dg-bogus "first argument of .main. should be .int." } */
+/* { dg-bogus ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-bogus "return type of .main. is not .int." "" { target *-*-* } 5 } */
+
diff --git a/gcc/testsuite/gcc.dg/pr30551-3.c b/gcc/testsuite/gcc.dg/pr30551-3.c
new file mode 100644
index 00000000000..120d45b8393
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551-3.c
@@ -0,0 +1,7 @@
+/* PR 30551 -Wmain is enabled by -pedantic-errors. */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+void main(char a) {} /* { dg-error "first argument of .main. should be .int." } */
+/* { dg-error ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-error "return type of .main. is not .int." "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/gcc.dg/pr30551-4.c b/gcc/testsuite/gcc.dg/pr30551-4.c
new file mode 100644
index 00000000000..4803dbac01d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551-4.c
@@ -0,0 +1,8 @@
+/* PR 30551 -Wmain is enabled by -pedantic-errors and can be disabled. */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors -Wno-main" } */
+
+void main(char a) {} /* { dg-bogus "first argument of .main. should be .int." } */
+/* { dg-bogus ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-bogus "return type of .main. is not .int." "" { target *-*-* } 5 } */
+
diff --git a/gcc/testsuite/gcc.dg/pr30551-5.c b/gcc/testsuite/gcc.dg/pr30551-5.c
new file mode 100644
index 00000000000..060ed016b3c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551-5.c
@@ -0,0 +1,7 @@
+/* PR 30551 -Wmain is enabled by -pedantic and can be disabled. */
+/* { dg-do compile } */
+/* { dg-options "-pedantic -Wno-main" } */
+
+void main(char a) {} /* { dg-bogus "first argument of .main. should be .int." } */
+/* { dg-bogus ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-bogus "return type of .main. is not .int." "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/gcc.dg/pr30551-6.c b/gcc/testsuite/gcc.dg/pr30551-6.c
new file mode 100644
index 00000000000..9c33cd143dd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551-6.c
@@ -0,0 +1,7 @@
+/* PR 30551 -Wmain is enabled by -pedantic. */
+/* { dg-do compile } */
+/* { dg-options "-pedantic" } */
+
+void main(char a) {} /* { dg-warning "first argument of .main. should be .int." } */
+/* { dg-warning ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-warning "return type of .main. is not .int." "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/gcc.dg/pr30551.c b/gcc/testsuite/gcc.dg/pr30551.c
new file mode 100644
index 00000000000..d6fdd8fab46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr30551.c
@@ -0,0 +1,7 @@
+/* PR 30551 -Wmain is enabled by -Wall. */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+void main(char a) {} /* { dg-warning "first argument of .main. should be .int." } */
+/* { dg-warning ".main. takes only zero or two arguments" "" { target *-*-* } 5 } */
+/* { dg-warning "return type of .main. is not .int." "" { target *-*-* } 5 } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-3.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-3.c
index 6103c400ecb..178e6a44822 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-3.c
@@ -1,3 +1,4 @@
+/* { dg-options "" } */
int main(int a, int b, int c, int d)
{
int e = (a & ~b) & (~c & d);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c
new file mode 100644
index 00000000000..3b23c36238e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-21.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+struct A {
+ struct B {
+ int i;
+ } b;
+} a;
+
+int foo (void)
+{
+ struct B *p = &a.b;
+ struct A *q = (struct A *) p;
+ return q->b.i;
+}
+
+int bar (void)
+{
+ struct A *p = &a;
+ struct B *q = (struct B *) p;
+ return q->i;
+}
+
+/* { dg-final { scan-tree-dump-times "a.b.i" 2 "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c
new file mode 100644
index 00000000000..01d11ecac87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-22.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+/* Make sure we propagate through builtins. */
+
+int foo (unsigned b)
+{
+ unsigned t = -1;
+ int x = b <= t;
+ long l = __builtin_expect (x, 0);
+ return l;
+}
+
+/* { dg-final { scan-tree-dump "return 1;" "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c
new file mode 100644
index 00000000000..ac7f068cfd1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-23.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+/* Make sure we propagate through POINTER_PLUS_EXPRs. */
+
+struct A {
+ int i[2];
+} a;
+
+int foo (void)
+{
+ struct A *p = &a;
+ int *q = (int *)p;
+ int *x = q + 1;
+ return *x;
+}
+
+/* { dg-final { scan-tree-dump "a.i\\\[1\\\]" "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index af102cd25e1..ff8af4f14dd 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -630,7 +630,7 @@ surely_varying_stmt_p (gimple stmt)
tree fndecl;
if (!gimple_call_lhs (stmt)
|| ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
- && DECL_BUILT_IN (fndecl)))
+ && !DECL_BUILT_IN (fndecl)))
return true;
}
@@ -988,18 +988,26 @@ ccp_fold (gimple stmt)
useless_type_conversion_p places for pointer type conversions
do not apply here. Substitution later will only substitute to
allowed places. */
- if ((subcode == NOP_EXPR || subcode == CONVERT_EXPR)
- && ((POINTER_TYPE_P (TREE_TYPE (lhs))
- && POINTER_TYPE_P (TREE_TYPE (op0))
- /* Do not allow differences in volatile qualification
- as this might get us confused as to whether a
- propagation destination statement is volatile
- or not. See PR36988. */
- && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
- == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
- || useless_type_conversion_p (TREE_TYPE (lhs),
- TREE_TYPE (op0))))
- return op0;
+ if (IS_CONVERT_EXPR_CODE_P (subcode)
+ && POINTER_TYPE_P (TREE_TYPE (lhs))
+ && POINTER_TYPE_P (TREE_TYPE (op0))
+ /* Do not allow differences in volatile qualification
+ as this might get us confused as to whether a
+ propagation destination statement is volatile
+ or not. See PR36988. */
+ && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
+ == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
+ {
+ tree tem;
+ /* Still try to generate a constant of correct type. */
+ if (!useless_type_conversion_p (TREE_TYPE (lhs),
+ TREE_TYPE (op0))
+ && ((tem = maybe_fold_offset_to_address
+ (op0, integer_zero_node, TREE_TYPE (lhs)))
+ != NULL_TREE))
+ return tem;
+ return op0;
+ }
return fold_unary (subcode, gimple_expr_type (stmt), op0);
}
@@ -1025,6 +1033,18 @@ ccp_fold (gimple stmt)
op1 = val->value;
}
+ /* Fold &foo + CST into an invariant reference if possible. */
+ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+ && TREE_CODE (op0) == ADDR_EXPR
+ && TREE_CODE (op1) == INTEGER_CST)
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree tem = maybe_fold_offset_to_address (op0, op1,
+ TREE_TYPE (lhs));
+ if (tem != NULL_TREE)
+ return tem;
+ }
+
return fold_binary (subcode, gimple_expr_type (stmt), op0, op1);
}
@@ -1948,15 +1968,15 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
so it needs to be removed and new COMPONENT_REF constructed.
The wrong COMPONENT_REF are often constructed by folding the
(type *)&object within the expression (type *)&object+offset */
- if (handled_component_p (base) && 0)
+ if (handled_component_p (base))
{
HOST_WIDE_INT sub_offset, size, maxsize;
tree newbase;
newbase = get_ref_base_and_extent (base, &sub_offset,
&size, &maxsize);
gcc_assert (newbase);
- gcc_assert (!(sub_offset & (BITS_PER_UNIT - 1)));
- if (size == maxsize)
+ if (size == maxsize
+ && !(sub_offset & (BITS_PER_UNIT - 1)))
{
base = newbase;
if (sub_offset)
@@ -1988,6 +2008,63 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
return ret;
}
+/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type
+ or &BASE[index] or by combination of those.
+
+ Before attempting the conversion strip off existing component refs. */
+
+tree
+maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type)
+{
+ tree t;
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
+ && POINTER_TYPE_P (orig_type));
+
+ t = maybe_fold_offset_to_reference (addr, offset, TREE_TYPE (orig_type));
+ if (t != NULL_TREE)
+ {
+ tree orig = addr;
+ tree ptr_type;
+
+ /* For __builtin_object_size to function correctly we need to
+ make sure not to fold address arithmetic so that we change
+ reference from one array to another. This would happen for
+ example for
+
+ struct X { char s1[10]; char s2[10] } s;
+ char *foo (void) { return &s.s2[-4]; }
+
+ where we need to avoid generating &s.s1[6]. As the C and
+ C++ frontends create different initial trees
+ (char *) &s.s1 + -4 vs. &s.s1[-4] we have to do some
+ sophisticated comparisons here. Note that checking for the
+ condition after the fact is easier than trying to avoid doing
+ the folding. */
+ STRIP_NOPS (orig);
+ if (TREE_CODE (orig) == ADDR_EXPR)
+ orig = TREE_OPERAND (orig, 0);
+ if ((TREE_CODE (orig) == ARRAY_REF
+ || (TREE_CODE (orig) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
+ && (TREE_CODE (t) == ARRAY_REF
+ || (TREE_CODE (t) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) == ARRAY_TYPE))
+ && !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
+ ? TREE_OPERAND (orig, 0) : orig,
+ TREE_CODE (t) == ARRAY_REF
+ ? TREE_OPERAND (t, 0) : t, 0))
+ return NULL_TREE;
+
+ ptr_type = build_pointer_type (TREE_TYPE (t));
+ if (!useless_type_conversion_p (orig_type, ptr_type))
+ return NULL_TREE;
+ return build_fold_addr_expr_with_type (t, ptr_type);
+ }
+
+ return NULL_TREE;
+}
+
/* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET).
Return the simplified expression, or NULL if nothing could be done. */
@@ -2223,16 +2300,10 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
if (POINTER_TYPE_P (TREE_TYPE (expr))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
- && (t = maybe_fold_offset_to_reference
- (TREE_OPERAND (expr, 0),
- integer_zero_node,
- TREE_TYPE (TREE_TYPE (expr)))))
- {
- tree ptr_type = build_pointer_type (TREE_TYPE (t));
- if (!useless_type_conversion_p (TREE_TYPE (expr), ptr_type))
- return NULL_TREE;
- t = build_fold_addr_expr_with_type (t, ptr_type);
- }
+ && (t = maybe_fold_offset_to_address (TREE_OPERAND (expr, 0),
+ integer_zero_node,
+ TREE_TYPE (TREE_TYPE (expr)))))
+ return t;
break;
/* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
@@ -2715,15 +2786,10 @@ fold_gimple_assign (gimple_stmt_iterator *si)
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
{
tree type = gimple_expr_type (stmt);
- tree t = maybe_fold_offset_to_reference (gimple_assign_rhs1 (stmt),
- integer_zero_node,
- TREE_TYPE (type));
+ tree t = maybe_fold_offset_to_address (gimple_assign_rhs1 (stmt),
+ integer_zero_node, type);
if (t)
- {
- tree ptr_type = build_pointer_type (TREE_TYPE (t));
- if (useless_type_conversion_p (type, ptr_type))
- return build_fold_addr_expr_with_type (t, ptr_type);
- }
+ return t;
}
break;
diff --git a/gcc/tree.h b/gcc/tree.h
index 5f5b37d4ef8..3f8065da736 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4744,6 +4744,7 @@ extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
extern void fold_undefer_and_ignore_overflow_warnings (void);
extern bool fold_deferring_overflow_warnings_p (void);
extern tree maybe_fold_offset_to_reference (tree, tree, tree);
+extern tree maybe_fold_offset_to_address (tree, tree, tree);
extern tree maybe_fold_stmt_addition (tree, tree, tree);
extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 355642c16c4..a0928ede3f6 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,38 @@
+2008-08-13 Sebastian Redl <sebastian.redl@getdesigned.at>
+
+ Add exception propagation support as per N2179.
+ * libsupc++/exception_ptr.h (exception_ptr, current_exception,
+ copy_exception, rethrow_exception): New file, implement exception
+ propagation.
+ * libsupc++/eh_ptr.cc (exception_ptr, current_exception,
+ rethrow_exception, __gxx_dependent_exception_cleanup): Likewise.
+ * libsupc++/unwind-cxx.h (__cxa_exception): Add reference count.
+ (__cxa_dependent_exception, __cxa_allocate_dependent_exception,
+ __cxa_free_dependent_exception, __get_dependent_exception_from_ue,
+ __GXX_INIT_DEPENDENT_EXCEPTION_CLASS, __is_dependent_exception,
+ __gxx_dependent_exception_class, __get_object_from_ue,
+ __get_object_from_ambiguous_exception): Add.
+ (__GXX_INIT_EXCEPTION_CLASS, __gxx_exception_class): Rename.
+ (__is_gxx_exception_class): Handle dependent exceptions.
+ * libsupc++/eh_arm.cc (__cxa_type_match): Likewise.
+ * libsupc++/eh_call.cc (__cxa_call_unexpected): Likewise.
+ * libsupc++/eh_personality.cc (__gxx_personality_*): Likewise.
+ * libsupc++/eh_type.cc (__cxa_current_exception_type): Likewise.
+ * libsupc++/eh_alloc.cc (__cxa_allocate_dependent_exception,
+ __cxa_free_dependent_exception): Add.
+ * libsupc++/eh_throw.cc (__gxx_exception_cleanup): Handle reference
+ counting.
+ * libsupc++/exception: Conditionally include exception_ptr.h.
+ * libsupc++/Makefile.am: Register new files.
+ * libsupc++/Makefile.in: Regenerate.
+ * config/abi/pre/gnu.ver: Add new symbols.
+ * testsuite/18_support/exception_ptr/current_exception.cc: Test the
+ core functionality of current_exception().
+ * testsuite/18_support/exception_ptr/rethrow_exception.cc: Test the
+ core functionality of rethrow_exception().
+ * testsuite/18_support/exception_ptr/lifespan.cc: Test the life span of
+ exception objects during exception propagation.
+
2008-08-12 Paolo Carlini <paolo.carlini@oracle.com>
PR libstdc++/37100
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 7b31a1cfa47..0ec4879ffd4 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -66,7 +66,9 @@ GLIBCXX_3.4 {
# std::condition_variable;
std::co[^n]*;
std::c[p-s]*;
- std::c[u-z]*;
+ std::cu[^r]*;
+# std::current_exception
+ std::c[v-z]*;
# std::[d-g]*;
std::d[a-d]*;
std::d[f-z]*;
@@ -112,10 +114,13 @@ GLIBCXX_3.4 {
std::n[^au]*;
std::nu[^m]*;
std::num[^e]*;
- std::[p-r]*;
std::ostrstream*;
std::out_of_range*;
std::overflow_error*;
+ std::[p-q]*;
+ std::r[^e]*;
+ std::re[^t]*;
+# std::rethrow_exception
std::set_new_handler*;
std::set_terminate*;
std::set_unexpected*;
@@ -1047,4 +1052,24 @@ CXXABI_1.3.3 {
_ZTIPu8char32_t;
_ZTIPKu8char32_t;
+ # exception_ptr
+ _ZNSt15__exception_ptr13exception_ptrC1Ev;
+ _ZNSt15__exception_ptr13exception_ptrC2Ev;
+ _ZNSt15__exception_ptr13exception_ptrC1ERKS0_;
+ _ZNSt15__exception_ptr13exception_ptrC2ERKS0_;
+ _ZNSt15__exception_ptr13exception_ptrC1EMS0_FvvE;
+ _ZNSt15__exception_ptr13exception_ptrC2EMS0_FvvE;
+ _ZNSt15__exception_ptr13exception_ptrD1Ev;
+ _ZNSt15__exception_ptr13exception_ptrD2Ev;
+ _ZNSt15__exception_ptr13exception_ptraSERKS0_;
+ _ZNKSt15__exception_ptr13exception_ptrcvMS0_FvvEEv;
+ _ZNKSt15__exception_ptr13exception_ptrntEv;
+ _ZNKSt15__exception_ptr13exception_ptr20__cxa_exception_typeEv;
+ _ZNSt15__exception_ptr13exception_ptr4swapERS0_;
+ _ZNSt15__exception_ptreqERKNS_13exception_ptrES2_;
+ _ZNSt15__exception_ptrneERKNS_13exception_ptrES2_;
+
+ _ZSt17current_exceptionv;
+ _ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE;
+
} CXXABI_1.3.2;
diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am
index c0412f0b8ed..680005fbf83 100644
--- a/libstdc++-v3/libsupc++/Makefile.am
+++ b/libstdc++-v3/libsupc++/Makefile.am
@@ -34,7 +34,7 @@ noinst_LTLIBRARIES = libsupc++convenience.la
headers = \
exception new typeinfo cxxabi.h cxxabi-forced.h exception_defines.h \
- initializer_list
+ initializer_list exception_ptr.h
if GLIBCXX_HOSTED
c_sources = \
@@ -60,6 +60,7 @@ sources = \
eh_exception.cc \
eh_globals.cc \
eh_personality.cc \
+ eh_ptr.cc \
eh_term_handler.cc \
eh_terminate.cc \
eh_throw.cc \
diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in
index 105aec63d8d..c3d1c6c6b43 100644
--- a/libstdc++-v3/libsupc++/Makefile.in
+++ b/libstdc++-v3/libsupc++/Makefile.in
@@ -79,7 +79,7 @@ am__libsupc___la_SOURCES_DIST = array_type_info.cc atexit_arm.cc \
bad_cast.cc bad_typeid.cc class_type_info.cc del_op.cc \
del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc eh_alloc.cc \
eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
- eh_exception.cc eh_globals.cc eh_personality.cc \
+ eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -91,7 +91,7 @@ am__objects_1 = array_type_info.lo atexit_arm.lo bad_cast.lo \
bad_typeid.lo class_type_info.lo del_op.lo del_opnt.lo \
del_opv.lo del_opvnt.lo dyncast.lo eh_alloc.lo eh_arm.lo \
eh_aux_runtime.lo eh_call.lo eh_catch.lo eh_exception.lo \
- eh_globals.lo eh_personality.lo eh_term_handler.lo \
+ eh_globals.lo eh_personality.lo eh_ptr.lo eh_term_handler.lo \
eh_terminate.lo eh_throw.lo eh_type.lo eh_unex_handler.lo \
enum_type_info.lo function_type_info.lo \
fundamental_type_info.lo guard.lo new_handler.lo new_op.lo \
@@ -107,7 +107,7 @@ am__libsupc__convenience_la_SOURCES_DIST = array_type_info.cc \
atexit_arm.cc bad_cast.cc bad_typeid.cc class_type_info.cc \
del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc \
eh_alloc.cc eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
- eh_exception.cc eh_globals.cc eh_personality.cc \
+ eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -356,7 +356,7 @@ toolexeclib_LTLIBRARIES = libsupc++.la
noinst_LTLIBRARIES = libsupc++convenience.la
headers = \
exception new typeinfo cxxabi.h cxxabi-forced.h exception_defines.h \
- initializer_list
+ initializer_list exception_ptr.h
@GLIBCXX_HOSTED_TRUE@c_sources = \
@GLIBCXX_HOSTED_TRUE@ cp-demangle.c
@@ -380,6 +380,7 @@ sources = \
eh_exception.cc \
eh_globals.cc \
eh_personality.cc \
+ eh_ptr.cc \
eh_term_handler.cc \
eh_terminate.cc \
eh_throw.cc \
diff --git a/libstdc++-v3/libsupc++/eh_alloc.cc b/libstdc++-v3/libsupc++/eh_alloc.cc
index 553c1c1e858..6bc46fc9a91 100644
--- a/libstdc++-v3/libsupc++/eh_alloc.cc
+++ b/libstdc++-v3/libsupc++/eh_alloc.cc
@@ -1,5 +1,5 @@
// -*- C++ -*- Allocate exception objects.
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008
// Free Software Foundation, Inc.
//
// This file is part of GCC.
@@ -89,6 +89,9 @@ typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
static bitmask_type emergency_used;
+static __cxa_dependent_exception dependents_buffer[EMERGENCY_OBJ_COUNT];
+static bitmask_type dependents_used;
+
namespace
{
// A single mutex controlling emergency allocations.
@@ -157,3 +160,66 @@ __cxxabiv1::__cxa_free_exception(void *vptr) throw()
else
free (ptr - sizeof (__cxa_exception));
}
+
+
+extern "C" __cxa_dependent_exception*
+__cxxabiv1::__cxa_allocate_dependent_exception() throw()
+{
+ __cxa_dependent_exception *ret;
+
+ ret = static_cast<__cxa_dependent_exception*>
+ (malloc (sizeof (__cxa_dependent_exception)));
+
+ if (!ret)
+ {
+ __gnu_cxx::__scoped_lock sentry(emergency_mutex);
+
+ bitmask_type used = dependents_used;
+ unsigned int which = 0;
+
+ while (used & 1)
+ {
+ used >>= 1;
+ if (++which >= EMERGENCY_OBJ_COUNT)
+ goto failed;
+ }
+
+ dependents_used |= (bitmask_type)1 << which;
+ ret = &dependents_buffer[which];
+
+ failed:;
+
+ if (!ret)
+ std::terminate ();
+ }
+
+ // We have an uncaught exception as soon as we allocate memory. This
+ // yields uncaught_exception() true during the copy-constructor that
+ // initializes the exception object. See Issue 475.
+ __cxa_eh_globals *globals = __cxa_get_globals ();
+ globals->uncaughtExceptions += 1;
+
+ memset (ret, 0, sizeof (__cxa_dependent_exception));
+
+ return ret;
+}
+
+
+extern "C" void
+__cxxabiv1::__cxa_free_dependent_exception
+ (__cxa_dependent_exception *vptr) throw()
+{
+ char *base = (char *) dependents_buffer;
+ char *ptr = (char *) vptr;
+ if (ptr >= base
+ && ptr < base + sizeof (dependents_buffer))
+ {
+ const unsigned int which
+ = (unsigned) (ptr - base) / sizeof (__cxa_dependent_exception);
+
+ __gnu_cxx::__scoped_lock sentry(emergency_mutex);
+ dependents_used &= ~((bitmask_type)1 << which);
+ }
+ else
+ free (vptr);
+}
diff --git a/libstdc++-v3/libsupc++/eh_arm.cc b/libstdc++-v3/libsupc++/eh_arm.cc
index 6f770e95663..f10bb41e5c0 100644
--- a/libstdc++-v3/libsupc++/eh_arm.cc
+++ b/libstdc++-v3/libsupc++/eh_arm.cc
@@ -1,5 +1,5 @@
// -*- C++ -*- ARM specific Exception handling support routines.
-// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -48,13 +48,19 @@ __cxa_type_match(_Unwind_Exception* ue_header,
{
bool forced_unwind = __is_gxx_forced_unwind_class(ue_header->exception_class);
bool foreign_exception = !forced_unwind && !__is_gxx_exception_class(ue_header->exception_class);
+ bool dependent_exception =
+ __is_dependent_exception(ue_header->exception_class);
__cxa_exception* xh = __get_exception_header_from_ue(ue_header);
+ __cxa_dependent_exception *dx = __get_dependent_exception_from_ue(ue_header);
const std::type_info* throw_type;
if (forced_unwind)
throw_type = &typeid(abi::__forced_unwind);
else if (foreign_exception)
throw_type = &typeid(abi::__foreign_exception);
+ else if (dependent_exception)
+ throw_type = __get_exception_header_from_obj
+ (dx->primaryException)->exceptionType;
else
throw_type = xh->exceptionType;
diff --git a/libstdc++-v3/libsupc++/eh_call.cc b/libstdc++-v3/libsupc++/eh_call.cc
index edf62188a6b..c0bced99533 100644
--- a/libstdc++-v3/libsupc++/eh_call.cc
+++ b/libstdc++-v3/libsupc++/eh_call.cc
@@ -1,5 +1,5 @@
// -*- C++ -*- Helpers for calling unextected and terminate
-// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -125,7 +125,7 @@ __cxa_call_unexpected(void* exc_obj_in)
__cxa_eh_globals* globals = __cxa_get_globals_fast();
__cxa_exception* new_xh = globals->caughtExceptions;
- void* new_ptr = new_xh + 1;
+ void* new_ptr = __gxx_get_object_from_ambiguous_exception (new_xh);
const std::type_info* catch_type;
int n;
bool bad_exception_allowed = false;
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc
index b7d957c4d37..12b54c16587 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -377,7 +377,7 @@ PERSONALITY_FUNCTION (int version,
const unsigned char *p;
_Unwind_Ptr landing_pad, ip;
int handler_switch_value;
- void* thrown_ptr = ue_header + 1;
+ void* thrown_ptr = 0;
bool foreign_exception;
int ip_before_insn = 0;
@@ -543,30 +543,33 @@ PERSONALITY_FUNCTION (int version,
bool saw_handler = false;
#ifdef __ARM_EABI_UNWINDER__
+ // ??? How does this work - more importantly, how does it interact with
+ // dependent exceptions?
throw_type = ue_header;
if (actions & _UA_FORCE_UNWIND)
{
__GXX_INIT_FORCED_UNWIND_CLASS(ue_header->exception_class);
- thrown_ptr = 0;
}
- else if (foreign_exception)
- thrown_ptr = 0;
+ else if (!foreign_exception)
+ thrown_ptr = __get_object_from_ue (ue_header);
#else
// During forced unwinding, match a magic exception type.
if (actions & _UA_FORCE_UNWIND)
{
throw_type = &typeid(abi::__forced_unwind);
- thrown_ptr = 0;
}
// With a foreign exception class, there's no exception type.
// ??? What to do about GNU Java and GNU Ada exceptions?
else if (foreign_exception)
{
throw_type = &typeid(abi::__foreign_exception);
- thrown_ptr = 0;
}
else
- throw_type = xh->exceptionType;
+ {
+ thrown_ptr = __get_object_from_ue (ue_header);
+ throw_type = __get_exception_header_from_obj
+ (thrown_ptr)->exceptionType;
+ }
#endif
while (1)
@@ -758,13 +761,14 @@ __cxa_call_unexpected (void *exc_obj_in)
__cxa_eh_globals *globals = __cxa_get_globals_fast ();
__cxa_exception *new_xh = globals->caughtExceptions;
- void *new_ptr = new_xh + 1;
+ void *new_ptr = __get_object_from_ambiguous_exception (new_xh);
// We don't quite have enough stuff cached; re-parse the LSDA.
parse_lsda_header (0, xh_lsda, &info);
// If this new exception meets the exception spec, allow it.
- if (check_exception_spec (&info, new_xh->exceptionType,
+ if (check_exception_spec (&info, __get_exception_header_from_obj
+ (new_ptr)->exceptionType,
new_ptr, xh_switch_value))
__throw_exception_again;
diff --git a/libstdc++-v3/libsupc++/eh_ptr.cc b/libstdc++-v3/libsupc++/eh_ptr.cc
new file mode 100644
index 00000000000..060b8eb2668
--- /dev/null
+++ b/libstdc++-v3/libsupc++/eh_ptr.cc
@@ -0,0 +1,236 @@
+// -*- C++ -*- Implement the members of exception_ptr.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+#include <bits/c++config.h>
+#include <exception>
+#include <exception_ptr.h>
+#include "unwind-cxx.h"
+
+using namespace __cxxabiv1;
+
+
+std::__exception_ptr::exception_ptr::exception_ptr() throw()
+ : _M_exception_object(0)
+{
+}
+
+
+std::__exception_ptr::exception_ptr::exception_ptr(void* obj) throw()
+ : _M_exception_object(obj)
+{
+ _M_addref();
+}
+
+
+std::__exception_ptr::exception_ptr::exception_ptr(__safe_bool) throw()
+ : _M_exception_object(0)
+{
+}
+
+
+std::__exception_ptr::exception_ptr::exception_ptr(
+ const exception_ptr& other) throw()
+ : _M_exception_object(other._M_exception_object)
+{
+ _M_addref();
+}
+
+
+std::__exception_ptr::exception_ptr::~exception_ptr() throw()
+{
+ _M_release();
+}
+
+
+std::__exception_ptr::exception_ptr&
+std::__exception_ptr::exception_ptr::operator=(
+ const exception_ptr& other) throw()
+{
+ exception_ptr(other).swap(*this);
+ return *this;
+}
+
+
+void
+std::__exception_ptr::exception_ptr::_M_addref() throw()
+{
+ if (_M_exception_object)
+ {
+ __cxa_exception *eh =
+ __get_exception_header_from_obj (_M_exception_object);
+ __sync_add_and_fetch (&eh->referenceCount, 1);
+ }
+}
+
+
+void
+std::__exception_ptr::exception_ptr::_M_release() throw()
+{
+ if (_M_exception_object)
+ {
+ __cxa_exception *eh =
+ __get_exception_header_from_obj (_M_exception_object);
+ if (__sync_sub_and_fetch (&eh->referenceCount, 1) == 0)
+ {
+ if (eh->exceptionDestructor)
+ eh->exceptionDestructor (_M_exception_object);
+
+ __cxa_free_exception (_M_exception_object);
+ _M_exception_object = 0;
+ }
+ }
+}
+
+
+void*
+std::__exception_ptr::exception_ptr::_M_get() const throw()
+{
+ return _M_exception_object;
+}
+
+
+void
+std::__exception_ptr::exception_ptr::_M_safe_bool_dummy()
+{
+}
+
+
+void
+std::__exception_ptr::exception_ptr::swap(exception_ptr &other) throw()
+{
+ void *tmp = _M_exception_object;
+ _M_exception_object = other._M_exception_object;
+ other._M_exception_object = tmp;
+}
+
+
+bool
+std::__exception_ptr::exception_ptr::operator!() const throw()
+{
+ return _M_exception_object == 0;
+}
+
+
+std::__exception_ptr::exception_ptr::operator __safe_bool() const throw()
+{
+ return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : 0;
+}
+
+
+const std::type_info*
+std::__exception_ptr::exception_ptr::__cxa_exception_type() const throw()
+{
+ __cxa_exception *eh = __get_exception_header_from_obj (_M_exception_object);
+ return eh->exceptionType;
+}
+
+
+bool std::__exception_ptr::operator==(const exception_ptr& lhs,
+ const exception_ptr& rhs) throw()
+{
+ return lhs._M_exception_object == rhs._M_exception_object;
+}
+
+
+bool std::__exception_ptr::operator!=(const exception_ptr& lhs,
+ const exception_ptr& rhs) throw()
+{
+ return !(lhs == rhs);
+}
+
+
+std::exception_ptr
+std::current_exception() throw()
+{
+ __cxa_eh_globals *globals = __cxa_get_globals ();
+ __cxa_exception *header = globals->caughtExceptions;
+
+ if (!header)
+ return std::exception_ptr();
+
+ // Since foreign exceptions can't be counted, we can't return them.
+ if (!__is_gxx_exception_class (header->unwindHeader.exception_class))
+ return std::exception_ptr();
+
+ return std::exception_ptr(
+ __get_object_from_ambiguous_exception (header));
+}
+
+
+static void
+__gxx_dependent_exception_cleanup (_Unwind_Reason_Code code,
+ _Unwind_Exception *exc)
+{
+ // This cleanup is set only for dependents.
+ __cxa_dependent_exception *dep = __get_dependent_exception_from_ue (exc);
+ __cxa_exception *header =
+ __get_exception_header_from_obj (dep->primaryException);
+
+ // We only want to be called through _Unwind_DeleteException.
+ // _Unwind_DeleteException in the HP-UX IA64 libunwind library
+ // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT
+ // like the GCC _Unwind_DeleteException function does.
+ if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
+ __terminate (header->terminateHandler);
+
+ if (__sync_sub_and_fetch (&header->referenceCount, 1) == 0)
+ {
+ if (header->exceptionDestructor)
+ header->exceptionDestructor (header + 1);
+
+ __cxa_free_exception (header + 1);
+ }
+}
+
+
+void
+std::rethrow_exception(std::exception_ptr ep)
+{
+ void *obj = ep._M_get();
+ __cxa_exception *eh = __get_exception_header_from_obj (obj);
+
+ __cxa_dependent_exception *dep = __cxa_allocate_dependent_exception ();
+ dep->primaryException = obj;
+ __sync_add_and_fetch (&eh->referenceCount, 1);
+
+ dep->unexpectedHandler = __unexpected_handler;
+ dep->terminateHandler = __terminate_handler;
+ __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class);
+ dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup;
+
+#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
+ _Unwind_SjLj_RaiseException (&dep->unwindHeader);
+#else
+ _Unwind_RaiseException (&dep->unwindHeader);
+#endif
+
+ // Some sort of unwinding error. Note that terminate is a handler.
+ __cxa_begin_catch (&dep->unwindHeader);
+ std::terminate ();
+}
diff --git a/libstdc++-v3/libsupc++/eh_throw.cc b/libstdc++-v3/libsupc++/eh_throw.cc
index b405f8f7c64..5887f26e9bb 100644
--- a/libstdc++-v3/libsupc++/eh_throw.cc
+++ b/libstdc++-v3/libsupc++/eh_throw.cc
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling routines for throwing.
-// Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -36,20 +36,23 @@ using namespace __cxxabiv1;
static void
__gxx_exception_cleanup (_Unwind_Reason_Code code, _Unwind_Exception *exc)
{
+ // This cleanup is set only for primaries.
__cxa_exception *header = __get_exception_header_from_ue (exc);
- // If we haven't been caught by a foreign handler, then this is
- // some sort of unwind error. In that case just die immediately.
+ // We only want to be called through _Unwind_DeleteException.
// _Unwind_DeleteException in the HP-UX IA64 libunwind library
- // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT
+ // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT
// like the GCC _Unwind_DeleteException function does.
if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
__terminate (header->terminateHandler);
- if (header->exceptionDestructor)
- header->exceptionDestructor (header + 1);
+ if (__sync_sub_and_fetch (&header->referenceCount, 1) == 0)
+ {
+ if (header->exceptionDestructor)
+ header->exceptionDestructor (header + 1);
- __cxa_free_exception (header + 1);
+ __cxa_free_exception (header + 1);
+ }
}
@@ -57,12 +60,14 @@ extern "C" void
__cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
void (*dest) (void *))
{
+ // Definitely a primary.
__cxa_exception *header = __get_exception_header_from_obj (obj);
+ header->referenceCount = 1;
header->exceptionType = tinfo;
header->exceptionDestructor = dest;
header->unexpectedHandler = __unexpected_handler;
header->terminateHandler = __terminate_handler;
- __GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class);
+ __GXX_INIT_PRIMARY_EXCEPTION_CLASS(header->unwindHeader.exception_class);
header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
diff --git a/libstdc++-v3/libsupc++/eh_type.cc b/libstdc++-v3/libsupc++/eh_type.cc
index 99627efdd97..03432976714 100644
--- a/libstdc++-v3/libsupc++/eh_type.cc
+++ b/libstdc++-v3/libsupc++/eh_type.cc
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling routines for catching.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -43,7 +43,15 @@ std::type_info *__cxa_current_exception_type ()
__cxa_eh_globals *globals = __cxa_get_globals ();
__cxa_exception *header = globals->caughtExceptions;
if (header)
- return header->exceptionType;
+ {
+ if (__is_dependent_exception (header->unwindHeader.exception_class))
+ {
+ __cxa_dependent_exception *de =
+ __get_dependent_exception_from_ue (&header->unwindHeader);
+ header = __get_exception_header_from_obj (de->primaryException);
+ }
+ return header->exceptionType;
+ }
else
return 0;
}
diff --git a/libstdc++-v3/libsupc++/exception b/libstdc++-v3/libsupc++/exception
index a7e2db78dd1..f1288211e98 100644
--- a/libstdc++-v3/libsupc++/exception
+++ b/libstdc++-v3/libsupc++/exception
@@ -1,7 +1,7 @@
// Exception Handling support header for -*- C++ -*-
// Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-// 2004, 2005, 2006, 2007
+// 2004, 2005, 2006, 2007, 2008
// Free Software Foundation
//
// This file is part of GCC.
@@ -110,6 +110,7 @@ namespace std
* result in a call of @c terminate() (15.5.1)."
*/
bool uncaught_exception() throw();
+
} // namespace std
_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
@@ -132,4 +133,8 @@ _GLIBCXX_END_NAMESPACE
#pragma GCC visibility pop
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#include <exception_ptr.h>
+#endif
+
#endif
diff --git a/libstdc++-v3/libsupc++/exception_ptr.h b/libstdc++-v3/libsupc++/exception_ptr.h
new file mode 100644
index 00000000000..77b0431c42f
--- /dev/null
+++ b/libstdc++-v3/libsupc++/exception_ptr.h
@@ -0,0 +1,169 @@
+// Exception Handling support header (exception_ptr class) for -*- C++ -*-
+
+// Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+// 2004, 2005, 2006, 2007, 2008
+// Free Software Foundation
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+/** @file exception_ptr.h
+ * This is an internal header file, included by other headers and the
+ * implementation. You should not attempt to use it directly.
+ */
+
+#ifndef __EXCEPTION_PTR_H__
+#define __EXCEPTION_PTR_H__
+
+#pragma GCC visibility push(default)
+
+#include <bits/c++config.h>
+
+extern "C++" {
+
+namespace std
+{
+ // Hide the free operators from other types
+ namespace __exception_ptr
+ {
+ /**
+ * @brief An opaque pointer to an arbitrary exception.
+ */
+ class exception_ptr;
+ }
+
+ using __exception_ptr::exception_ptr;
+
+ /** Obtain an %exception_ptr to the currently handled exception. If there
+ * is none, or the currently handled exception is foreign, return the null
+ * value.
+ */
+ exception_ptr current_exception() throw();
+
+ /// Throw the object pointed to by the %exception_ptr.
+ void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__));
+
+ /// Obtain an %exception_ptr pointing to a copy of the supplied object.
+ template <class _Ex>
+ exception_ptr copy_exception(_Ex __ex) throw();
+
+
+ namespace __exception_ptr
+ {
+ bool operator==(const exception_ptr&,
+ const exception_ptr&) throw();
+ bool operator!=(const exception_ptr&,
+ const exception_ptr&) throw();
+
+ class exception_ptr
+ {
+ void* _M_exception_object;
+
+ explicit exception_ptr(void* __e) throw();
+
+ void _M_addref() throw();
+ void _M_release() throw();
+
+ void *_M_get() const throw();
+
+ void _M_safe_bool_dummy();
+
+ friend exception_ptr std::current_exception() throw();
+ friend void std::rethrow_exception(exception_ptr);
+
+ public:
+ exception_ptr() throw();
+
+ typedef void (exception_ptr::*__safe_bool)();
+
+ // For construction from nullptr or 0.
+ exception_ptr(__safe_bool) throw();
+
+ exception_ptr(const exception_ptr&) throw();
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ exception_ptr(exception_ptr&& __o) throw()
+ : _M_exception_object(__o._M_exception_object)
+ {
+ __o._M_exception_object = 0;
+ }
+#endif
+
+ exception_ptr& operator=(const exception_ptr&) throw();
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ exception_ptr& operator=(exception_ptr&& __o) throw()
+ {
+ exception_ptr(__o).swap(*this);
+ return *this;
+ }
+#endif
+
+ ~exception_ptr() throw();
+
+ void swap(exception_ptr&) throw();
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ void swap(exception_ptr &&__o) throw()
+ {
+ void *__tmp = _M_exception_object;
+ _M_exception_object = __o._M_exception_object;
+ __o._M_exception_object = __tmp;
+ }
+#endif
+
+ bool operator!() const throw();
+ operator __safe_bool() const throw();
+
+ friend bool operator==(const exception_ptr&,
+ const exception_ptr&) throw();
+
+ const type_info *__cxa_exception_type() const throw();
+ };
+
+ } // namespace __exception_ptr
+
+
+ template <class _Ex>
+ exception_ptr copy_exception(_Ex __ex) throw()
+ {
+ try
+ {
+ throw __ex;
+ }
+ catch(...)
+ {
+ return current_exception ();
+ }
+ }
+
+} // namespace std
+
+} // extern "C++"
+
+#pragma GCC visibility pop
+
+#endif
diff --git a/libstdc++-v3/libsupc++/unwind-cxx.h b/libstdc++-v3/libsupc++/unwind-cxx.h
index 75874fc5da4..dc3fdc462d9 100644
--- a/libstdc++-v3/libsupc++/unwind-cxx.h
+++ b/libstdc++-v3/libsupc++/unwind-cxx.h
@@ -1,5 +1,5 @@
// -*- C++ -*- Exception handling and frame unwind runtime interface routines.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -45,12 +45,15 @@
namespace __cxxabiv1
{
-// A C++ exception object consists of a header, which is a wrapper around
-// an unwind object header with additional C++ specific information,
+// A primary C++ exception object consists of a header, which is a wrapper
+// around an unwind object header with additional C++ specific information,
// followed by the exception object itself.
struct __cxa_exception
-{
+{
+ // Manage this header.
+ std::size_t referenceCount;
+
// Manage the exception object itself.
std::type_info *exceptionType;
void (*exceptionDestructor)(void *);
@@ -87,6 +90,47 @@ struct __cxa_exception
_Unwind_Exception unwindHeader;
};
+// A dependent C++ exception object consists of a wrapper around an unwind
+// object header with additional C++ specific information, containing a pointer
+// to a primary exception object.
+
+struct __cxa_dependent_exception
+{
+ // The primary exception this thing depends on.
+ void *primaryException;
+
+ // The C++ standard has entertaining rules wrt calling set_terminate
+ // and set_unexpected in the middle of the exception cleanup process.
+ std::unexpected_handler unexpectedHandler;
+ std::terminate_handler terminateHandler;
+
+ // The caught exception stack threads through here.
+ __cxa_exception *nextException;
+
+ // How many nested handlers have caught this exception. A negated
+ // value is a signal that this object has been rethrown.
+ int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+ // Stack of exceptions in cleanups.
+ __cxa_exception* nextPropagatingException;
+
+ // The nuber of active cleanup handlers for this exception.
+ int propagationCount;
+#else
+ // Cache parsed handler data from the personality routine Phase 1
+ // for Phase 2 and __cxa_call_unexpected.
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ _Unwind_Ptr catchTemp;
+ void *adjustedPtr;
+#endif
+
+ // The generic exception header. Must be last.
+ _Unwind_Exception unwindHeader;
+};
+
// Each thread in a C++ program has access to a __cxa_eh_globals object.
struct __cxa_eh_globals
{
@@ -105,12 +149,20 @@ struct __cxa_eh_globals
extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
-// Allocate memory for the exception plus the thown object.
+// Allocate memory for the primary exception plus the thrown object.
extern "C" void *__cxa_allocate_exception(std::size_t thrown_size) throw();
-// Free the space allocated for the exception.
+// Free the space allocated for the primary exception.
extern "C" void __cxa_free_exception(void *thrown_exception) throw();
+// Allocate memory for a dependent exception.
+extern "C" __cxa_dependent_exception*
+__cxa_allocate_dependent_exception() throw();
+
+// Free the space allocated for the dependent exception.
+extern "C" void
+__cxa_free_dependent_exception(__cxa_dependent_exception *ex) throw();
+
// Throw the exception.
extern "C" void __cxa_throw (void *thrown_exception,
std::type_info *tinfo,
@@ -173,6 +225,12 @@ __get_exception_header_from_ue (_Unwind_Exception *exc)
return reinterpret_cast<__cxa_exception *>(exc + 1) - 1;
}
+static inline __cxa_dependent_exception *
+__get_dependent_exception_from_ue (_Unwind_Exception *exc)
+{
+ return reinterpret_cast<__cxa_dependent_exception *>(exc + 1) - 1;
+}
+
#ifdef __ARM_EABI_UNWINDER__
static inline bool
__is_gxx_exception_class(_Unwind_Exception_Class c)
@@ -185,11 +243,19 @@ __is_gxx_exception_class(_Unwind_Exception_Class c)
&& c[4] == 'C'
&& c[5] == '+'
&& c[6] == '+'
- && c[7] == '\0';
+ && (c[7] == '\0' || c[7] == '\x01');
+}
+
+// Only checks for primary or dependent, but not that it is a C++ exception at
+// all.
+static inline bool
+__is_dependent_exception(_Unwind_Exception_Class c)
+{
+ return c[7] == '\x01';
}
static inline void
-__GXX_INIT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
+__GXX_INIT_PRIMARY_EXCEPTION_CLASS(_Unwind_Exception_Class c)
{
c[0] = 'G';
c[1] = 'N';
@@ -201,6 +267,19 @@ __GXX_INIT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
c[7] = '\0';
}
+static inline void
+__GXX_INIT_DEPENDENT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
+{
+ c[0] = 'G';
+ c[1] = 'N';
+ c[2] = 'U';
+ c[3] = 'C';
+ c[4] = 'C';
+ c[5] = '+';
+ c[6] = '+';
+ c[7] = '\x01';
+}
+
static inline bool
__is_gxx_forced_unwind_class(_Unwind_Exception_Class c)
{
@@ -233,8 +312,8 @@ __gxx_caught_object(_Unwind_Exception* eo)
return (void*)eo->barrier_cache.bitpattern[0];
}
#else // !__ARM_EABI_UNWINDER__
-// This is the exception class we report -- "GNUCC++\0".
-const _Unwind_Exception_Class __gxx_exception_class
+// This is the primary exception class we report -- "GNUCC++\0".
+const _Unwind_Exception_Class __gxx_primary_exception_class
= ((((((((_Unwind_Exception_Class) 'G'
<< 8 | (_Unwind_Exception_Class) 'N')
<< 8 | (_Unwind_Exception_Class) 'U')
@@ -244,13 +323,36 @@ const _Unwind_Exception_Class __gxx_exception_class
<< 8 | (_Unwind_Exception_Class) '+')
<< 8 | (_Unwind_Exception_Class) '\0');
+// This is the dependent (from std::rethrow_exception) exception class we report
+// "GNUCC++\x01"
+const _Unwind_Exception_Class __gxx_dependent_exception_class
+= ((((((((_Unwind_Exception_Class) 'G'
+ << 8 | (_Unwind_Exception_Class) 'N')
+ << 8 | (_Unwind_Exception_Class) 'U')
+ << 8 | (_Unwind_Exception_Class) 'C')
+ << 8 | (_Unwind_Exception_Class) 'C')
+ << 8 | (_Unwind_Exception_Class) '+')
+ << 8 | (_Unwind_Exception_Class) '+')
+ << 8 | (_Unwind_Exception_Class) '\x01');
+
static inline bool
__is_gxx_exception_class(_Unwind_Exception_Class c)
{
- return c == __gxx_exception_class;
+ return c == __gxx_primary_exception_class
+ || c == __gxx_dependent_exception_class;
}
-#define __GXX_INIT_EXCEPTION_CLASS(c) c = __gxx_exception_class
+// Only checks for primary or dependent, but not that it is a C++ exception at
+// all.
+static inline bool
+__is_dependent_exception(_Unwind_Exception_Class c)
+{
+ return (c & 1);
+}
+
+#define __GXX_INIT_PRIMARY_EXCEPTION_CLASS(c) c = __gxx_primary_exception_class
+#define __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(c) \
+ c = __gxx_dependent_exception_class
// GNU C++ personality routine, Version 0.
extern "C" _Unwind_Reason_Code __gxx_personality_v0
@@ -265,11 +367,27 @@ extern "C" _Unwind_Reason_Code __gxx_personality_sj0
static inline void*
__gxx_caught_object(_Unwind_Exception* eo)
{
+ // Bad as it looks, this actually works for dependent exceptions too.
__cxa_exception* header = __get_exception_header_from_ue (eo);
return header->adjustedPtr;
}
#endif // !__ARM_EABI_UNWINDER__
+static inline void*
+__get_object_from_ue(_Unwind_Exception* eo) throw()
+{
+ return __is_dependent_exception (eo->exception_class) ?
+ __get_dependent_exception_from_ue (eo)->primaryException :
+ eo + 1;
+}
+
+static inline void *
+__get_object_from_ambiguous_exception(__cxa_exception *p_or_d) throw()
+{
+ return __get_object_from_ue (&p_or_d->unwindHeader);
+}
+
+
} /* namespace __cxxabiv1 */
#pragma GCC visibility pop
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc
new file mode 100644
index 00000000000..d4a63e4b001
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/current_exception.cc
@@ -0,0 +1,90 @@
+// { dg-options "-std=gnu++0x" }
+// 2008-05-25 Sebastian Redl <sebastian.redl@getdesigned.at>
+
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// current_exception() under various conditions.
+
+#include <exception>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ exception_ptr ep = current_exception();
+ VERIFY( !ep );
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ try {
+ throw 0;
+ } catch(...) {
+ exception_ptr ep = current_exception();
+ VERIFY( ep );
+ }
+}
+
+void test03()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ try {
+ throw exception();
+ } catch(std::exception&) {
+ exception_ptr ep = current_exception();
+ VERIFY( ep );
+ }
+}
+
+void test04()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ try {
+ throw 0;
+ } catch(...) {
+ exception_ptr ep1 = current_exception();
+ try {
+ throw 0;
+ } catch(...) {
+ exception_ptr ep2 = current_exception();
+ VERIFY( ep1 != ep2 );
+ }
+ exception_ptr ep3 = current_exception();
+ // Not guaranteed by standard, but by this implementation.
+ VERIFY( ep1 == ep3 );
+ }
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc
new file mode 100644
index 00000000000..1107a2ece60
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/lifespan.cc
@@ -0,0 +1,188 @@
+// { dg-options "-std=gnu++0x" }
+// 2008-05-25 Sebastian Redl <sebastian.redl@getdesigned.at>
+
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// Tests the life span of the exception object.
+
+#include <exception>
+#include <testsuite_hooks.h>
+
+bool may_destruct = false;
+
+class destructing
+{
+ mutable bool copied;
+
+public:
+ destructing() : copied(false) { }
+ destructing(const destructing &o) : copied(false) { o.copied = true; }
+ ~destructing() { VERIFY( copied || may_destruct ); }
+};
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ // Test the destructing class.
+ {
+ destructing *d = new destructing;
+ destructing d2(*d);
+ delete d;
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ try {
+ throw destructing();
+ } catch(...) {
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+void test03()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ try {
+ throw destructing();
+ } catch(...) {
+ {
+ exception_ptr ep = current_exception();
+ }
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+void test04()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ {
+ exception_ptr ep;
+ try {
+ throw destructing();
+ } catch(...) {
+ ep = current_exception();
+ }
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+void test05_helper()
+{
+ using namespace std;
+ try {
+ throw destructing();
+ } catch(...) {
+ exception_ptr ep = current_exception();
+ rethrow_exception(ep);
+ }
+}
+
+void test05()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ try {
+ test05_helper();
+ } catch(...) {
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+void test06_helper()
+{
+ using namespace std;
+ try {
+ throw destructing();
+ } catch(...) {
+ exception_ptr ep = current_exception();
+ throw;
+ }
+}
+
+void test06()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ try {
+ test06_helper();
+ } catch(...) {
+ may_destruct = true;
+ }
+ may_destruct = false;
+}
+
+std::exception_ptr gep;
+
+void test99()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ may_destruct = false;
+
+ try {
+ throw destructing();
+ } catch(...) {
+ gep = current_exception();
+ }
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+
+ test99();
+ may_destruct = true;
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/rethrow_exception.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/rethrow_exception.cc
new file mode 100644
index 00000000000..96d38d5eba3
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/rethrow_exception.cc
@@ -0,0 +1,113 @@
+// { dg-options "-std=gnu++0x" }
+// 2008-05-25 Sebastian Redl <sebastian.redl@getdesigned.at>
+
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// rethrow_exception() and preservation of data
+
+#include <exception>
+#include <typeinfo>
+#include <cstring>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ try {
+ rethrow_exception(copy_exception(0));
+ } catch(...) {
+ }
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ try {
+ rethrow_exception(copy_exception(runtime_error("test")));
+ } catch(exception &e) {
+ VERIFY( typeid(e) == typeid(runtime_error) );
+ VERIFY( strcmp(e.what(), "test") == 0 );
+ }
+}
+
+void test03()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ exception_ptr ep;
+ try {
+ throw 0;
+ } catch(...) {
+ ep = current_exception();
+ }
+ try {
+ rethrow_exception(ep);
+ } catch(...) {
+ }
+}
+
+void test04()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ // Weave the exceptions in an attempt to confuse the machinery.
+ try {
+ throw 0;
+ } catch(...) {
+ exception_ptr ep1 = current_exception();
+ try {
+ throw 1;
+ } catch(...) {
+ exception_ptr ep2 = current_exception();
+ try {
+ rethrow_exception(ep1);
+ } catch(...) {
+ try {
+ rethrow_exception(ep2);
+ } catch(...) {
+ try {
+ rethrow_exception(ep1);
+ } catch(...) {
+ }
+ try {
+ rethrow_exception(ep2);
+ } catch(...) {
+ }
+ }
+ }
+ }
+ }
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+
+ return 0;
+}