diff options
author | H.J. Lu <hongjiu.lu@intel.com> | 2008-08-13 18:35:31 +0000 |
---|---|---|
committer | H.J. Lu <hongjiu.lu@intel.com> | 2008-08-13 18:35:31 +0000 |
commit | 66c302abe513b7c3c2d711827564c30e5cedb624 (patch) | |
tree | d5cbc9d3a8b9b7319f01197ce943d6d8cef81f2a | |
parent | 596835d282b25c2ab724c47db5694f0b05090031 (diff) |
Merged with trunk at revision 139065.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/stack@139066 138bc75d-0d04-0410-961f-82ee72b054a4
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 (®_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; +} |