mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 12:00:03 -05:00
Compare commits
23 Commits
master
...
devel/noth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c756ee328c | ||
|
|
c4ab1c5710 | ||
|
|
f5b29909d5 | ||
|
|
da431b3514 | ||
|
|
cd716809b8 | ||
|
|
0d0df5179b | ||
|
|
1a736e2570 | ||
|
|
132a0acfde | ||
|
|
27be11a6b2 | ||
|
|
5a924600ea | ||
|
|
97933e9596 | ||
|
|
5f1a438ba6 | ||
|
|
6db81730ef | ||
|
|
079ca47d41 | ||
|
|
7ec7872003 | ||
|
|
47c2d0f6e0 | ||
|
|
d1a84d379d | ||
|
|
70505f5757 | ||
|
|
ba70ece436 | ||
|
|
9a70651a21 | ||
|
|
b602de4ed9 | ||
|
|
c16d4a0ae1 | ||
|
|
9b53c7f948 |
@@ -1211,6 +1211,30 @@ skip_in_fields_list_p (tree t)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if T2 is derived form T1. */
|
||||
|
||||
bool
|
||||
odr_equivalent_or_derived_p (tree t1, tree t2)
|
||||
{
|
||||
if (in_lto_p)
|
||||
{
|
||||
if (odr_types_equivalent_p (t1, t2))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
|
||||
return true;
|
||||
}
|
||||
if (!TYPE_BINFO (t2))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (t2)); i++)
|
||||
if (odr_equivalent_or_derived_p
|
||||
(t1, BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (t2), i))))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compare T1 and T2, report ODR violations if WARN is true and set
|
||||
WARNED to true if anything is reported. Return true if types match.
|
||||
If true is returned, the types are also compatible in the sense of
|
||||
|
||||
@@ -106,6 +106,7 @@ cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT,
|
||||
void warn_types_mismatch (tree t1, tree t2, location_t loc1 = UNKNOWN_LOCATION,
|
||||
location_t loc2 = UNKNOWN_LOCATION);
|
||||
bool odr_or_derived_type_p (const_tree t);
|
||||
bool odr_equivalent_or_derived_p (tree t1, tree t2);
|
||||
bool odr_types_equivalent_p (tree type1, tree type2);
|
||||
bool odr_type_violation_reported_p (tree type);
|
||||
tree prevailing_odr_type (tree type);
|
||||
|
||||
@@ -855,11 +855,12 @@ make_edges_bb (basic_block bb, struct omp_region **pcur_region, int *pomp_index)
|
||||
|
||||
if (!last)
|
||||
return ret;
|
||||
|
||||
|
||||
update_stmt_eh_region(last);
|
||||
switch (gimple_code (last))
|
||||
{
|
||||
case GIMPLE_GOTO:
|
||||
if (make_goto_expr_edges (bb))
|
||||
if (make_goto_expr_edges (bb))
|
||||
ret = 1;
|
||||
fallthru = false;
|
||||
break;
|
||||
|
||||
369
gcc/tree-eh.cc
369
gcc/tree-eh.cc
@@ -47,6 +47,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "attribs.h"
|
||||
#include "asan.h"
|
||||
#include "gimplify.h"
|
||||
#include "print-tree.h"
|
||||
#include "ipa-utils.h"
|
||||
#include "print-tree.h"
|
||||
#include "ipa-utils.h"
|
||||
#include "hash-set.h"
|
||||
|
||||
/* In some instances a tree and a gimple need to be stored in a same table,
|
||||
i.e. in hash tables. This is a structure to do this. */
|
||||
@@ -2271,6 +2276,212 @@ make_eh_dispatch_edges (geh_dispatch *stmt)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
same_or_derived_type (tree t1, tree t2)
|
||||
{
|
||||
t1 = TYPE_MAIN_VARIANT (t1);
|
||||
t2 = TYPE_MAIN_VARIANT (t2);
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
while ((TREE_CODE (t1) == POINTER_TYPE || TREE_CODE (t1) == REFERENCE_TYPE)
|
||||
&& TREE_CODE (t1) == TREE_CODE (t2))
|
||||
{
|
||||
t1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1));
|
||||
t2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2));
|
||||
if (TREE_CODE (t1) == VOID_TYPE)
|
||||
return true;
|
||||
}
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
if (TREE_CODE (t2) == NULLPTR_TYPE && TREE_CODE (t1) == POINTER_TYPE)
|
||||
return true;
|
||||
if (!AGGREGATE_TYPE_P (t1) || !AGGREGATE_TYPE_P (t2))
|
||||
return false;
|
||||
return odr_equivalent_or_derived_p (t1, t2);
|
||||
}
|
||||
|
||||
// Check if a region can handle any of the given exception types
|
||||
static bool
|
||||
match_lp (eh_region region, vec<tree> *exception_types)
|
||||
{
|
||||
// Ensure the region is of type ERT_TRY
|
||||
if (region && region->type == ERT_TRY)
|
||||
{
|
||||
eh_catch_d *catch_handler = region->u.eh_try.first_catch;
|
||||
|
||||
while (catch_handler)
|
||||
{
|
||||
tree type_list = catch_handler->type_list;
|
||||
|
||||
if (type_list == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (tree t = type_list; t; t = TREE_CHAIN (t))
|
||||
{
|
||||
tree type = TREE_VALUE (t);
|
||||
for (unsigned i = 0; i < exception_types->length (); ++i)
|
||||
{
|
||||
// match found or a catch-all handler (NULL)
|
||||
if (!type
|
||||
|| same_or_derived_type (type, (*exception_types)[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch_handler = catch_handler->next_catch;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
unlink_eh_region (eh_region region)
|
||||
{
|
||||
eh_region *link;
|
||||
|
||||
// Check if region is root
|
||||
if (!region->outer)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
return;
|
||||
}
|
||||
|
||||
link = ®ion->outer->inner;
|
||||
|
||||
while (*link && *link != region)
|
||||
{
|
||||
link = &(*link)->next_peer;
|
||||
}
|
||||
|
||||
// Ensure the region is in the peer chain
|
||||
gcc_assert (*link == region);
|
||||
|
||||
*link = region->next_peer;
|
||||
|
||||
region->outer = NULL;
|
||||
region->next_peer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
reinsert_eh_region (eh_region region, eh_region new_outer)
|
||||
{
|
||||
region->outer = new_outer;
|
||||
|
||||
// Insert region as the inner of new_outer, or at the top of the tree
|
||||
if (new_outer)
|
||||
{
|
||||
region->next_peer = new_outer->inner;
|
||||
new_outer->inner = region;
|
||||
}
|
||||
else
|
||||
{
|
||||
region->next_peer = cfun->eh->region_tree;
|
||||
cfun->eh->region_tree = region;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to update landing pad and region in throw_stmt_table for a given
|
||||
statement */
|
||||
void
|
||||
update_stmt_eh_region (gimple *stmt)
|
||||
{
|
||||
auto_vec<tree> exception_types;
|
||||
if (!stmt_throw_types (cfun, stmt, &exception_types))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
eh_region region;
|
||||
|
||||
int lp_nr = lookup_stmt_eh_lp_fn (cfun, stmt);
|
||||
if (lp_nr <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr);
|
||||
if (!lp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
region = lp->region;
|
||||
eh_region resx_region = NULL;
|
||||
|
||||
bool update = false;
|
||||
if (gimple_code (stmt) == GIMPLE_RESX)
|
||||
resx_region = get_eh_region_from_number (
|
||||
gimple_resx_region (as_a<gresx *> (stmt)));
|
||||
|
||||
// Walk up the region tree
|
||||
while (region)
|
||||
{
|
||||
switch (region->type)
|
||||
{
|
||||
case ERT_CLEANUP:
|
||||
if (!update)
|
||||
return;
|
||||
|
||||
if (gimple_code (stmt) == GIMPLE_RESX)
|
||||
{
|
||||
unlink_eh_region (resx_region);
|
||||
reinsert_eh_region (resx_region, region);
|
||||
}
|
||||
|
||||
remove_stmt_from_eh_lp_fn (cfun, stmt);
|
||||
record_stmt_eh_region (region, stmt);
|
||||
return;
|
||||
|
||||
case ERT_TRY:
|
||||
if (match_lp (region, &exception_types))
|
||||
{
|
||||
if (!update)
|
||||
return;
|
||||
if (gimple_code (stmt) == GIMPLE_RESX)
|
||||
{
|
||||
unlink_eh_region (resx_region);
|
||||
reinsert_eh_region (resx_region, region);
|
||||
}
|
||||
|
||||
remove_stmt_from_eh_lp_fn (cfun, stmt);
|
||||
record_stmt_eh_region (region, stmt);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERT_MUST_NOT_THROW:
|
||||
// Undefined behavior, leave edge unchanged
|
||||
return;
|
||||
|
||||
case ERT_ALLOWED_EXCEPTIONS:
|
||||
/* FIXME: match_lp will always return false. */
|
||||
if (!match_lp (region, &exception_types))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
region = region->outer;
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (!update)
|
||||
return;
|
||||
|
||||
if (gimple_code (stmt) == GIMPLE_RESX)
|
||||
{
|
||||
unlink_eh_region (resx_region);
|
||||
reinsert_eh_region (resx_region, NULL);
|
||||
}
|
||||
remove_stmt_from_eh_lp_fn (cfun, stmt);
|
||||
}
|
||||
|
||||
/* Create the single EH edge from STMT to its nearest landing pad,
|
||||
if there is such a landing pad within the current function. */
|
||||
|
||||
@@ -2913,6 +3124,164 @@ stmt_could_throw_1_p (gassign *stmt)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
extract_types_for_call (gcall *call_stmt, vec<tree> *ret_vector)
|
||||
{
|
||||
tree callee = gimple_call_fndecl (call_stmt);
|
||||
if (callee == NULL_TREE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (callee)), "__cxa_throw") == 0)
|
||||
{
|
||||
// Extracting exception type
|
||||
tree exception_type_info = gimple_call_arg (call_stmt, 1);
|
||||
if (exception_type_info && TREE_CODE (exception_type_info) == ADDR_EXPR)
|
||||
{
|
||||
exception_type_info = TREE_OPERAND (exception_type_info, 0);
|
||||
}
|
||||
if (exception_type_info && TREE_CODE (exception_type_info) == VAR_DECL)
|
||||
{
|
||||
// Converting the typeinfo to a compile-time type
|
||||
tree exception_type
|
||||
= TREE_TYPE (decl_assembler_name (exception_type_info));
|
||||
if (exception_type)
|
||||
{
|
||||
ret_vector->safe_push (exception_type);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Determine which types can be thrown by a GIMPLE statement and convert them
|
||||
* to compile-time types */
|
||||
bool
|
||||
stmt_throw_types (function *, gimple *stmt, vec<tree> *ret_vector)
|
||||
{
|
||||
if (!flag_exceptions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool type_exists = true;
|
||||
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
case GIMPLE_RESX:
|
||||
type_exists = extract_types_for_resx (as_a<gresx *> (stmt), ret_vector);
|
||||
return type_exists;
|
||||
|
||||
case GIMPLE_CALL:
|
||||
type_exists = extract_types_for_call (as_a<gcall *> (stmt), ret_vector);
|
||||
/* FIXME: if type exists we should have always vector nonempty. */
|
||||
return type_exists && !ret_vector->is_empty ();
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// To get the all exception types from a resx stmt (iterative version)
|
||||
bool
|
||||
extract_types_for_resx (gimple *resx_stmt, vec<tree> *ret_vector)
|
||||
{
|
||||
basic_block start_bb = gimple_bb (resx_stmt);
|
||||
hash_set<basic_block> visited_blocks;
|
||||
vec<basic_block> block_stack;
|
||||
|
||||
block_stack.safe_push(start_bb);
|
||||
|
||||
while (!block_stack.is_empty())
|
||||
{
|
||||
basic_block bb = block_stack.pop();
|
||||
if (visited_blocks.contains(bb))
|
||||
continue;
|
||||
|
||||
visited_blocks.add(bb);
|
||||
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
gimple_stmt_iterator gsi = gsi_last_bb(bb);
|
||||
gimple *last_stmt = gsi_stmt(gsi);
|
||||
|
||||
|
||||
FOR_EACH_EDGE(e, ei, bb->preds)
|
||||
{
|
||||
basic_block pred_bb = e->src;
|
||||
|
||||
if (e->flags & EDGE_EH)
|
||||
{
|
||||
gimple_stmt_iterator pred_gsi = gsi_last_bb(pred_bb);
|
||||
gimple *pred_last_stmt = gsi_stmt(pred_gsi);
|
||||
|
||||
if (gimple_code(pred_last_stmt) == GIMPLE_CALL)
|
||||
{
|
||||
if (!extract_types_for_call(as_a<gcall*>(pred_last_stmt), ret_vector))
|
||||
return false;
|
||||
}
|
||||
else if (gimple_code(pred_last_stmt) == GIMPLE_RESX)
|
||||
{
|
||||
// Add the predecessor block to the stack for further exploration
|
||||
block_stack.safe_push(pred_bb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
block_stack.safe_push(pred_bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear_aux_for_blocks();
|
||||
return true;
|
||||
}
|
||||
|
||||
// To get the types being thrown outside of a function
|
||||
bool
|
||||
extract_fun_resx_types (function *fun, vec<tree> *ret_vector)
|
||||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator gsi;
|
||||
hash_set<tree> types;
|
||||
|
||||
FOR_EACH_BB_FN (bb, fun)
|
||||
{
|
||||
bb->aux = (void *)1;
|
||||
gsi = gsi_last_bb (bb);
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
auto_vec<tree> resx_types;
|
||||
|
||||
if (!stmt || !stmt_can_throw_external (fun, stmt))
|
||||
continue;
|
||||
|
||||
if (gimple_code (stmt) == GIMPLE_RESX)
|
||||
{
|
||||
if (!extract_types_for_resx (stmt, &resx_types))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (gimple_code (stmt) == GIMPLE_CALL)
|
||||
{
|
||||
if (!extract_types_for_call (as_a<gcall *> (stmt), &resx_types))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < resx_types.length (); ++i)
|
||||
{
|
||||
tree type = resx_types[i];
|
||||
types.add (type);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = types.begin (); it != types.end (); ++it)
|
||||
{
|
||||
ret_vector->safe_push (*it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return true if statement STMT within FUN could throw an exception. */
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
|
||||
typedef struct eh_region_d *eh_region;
|
||||
typedef struct eh_landing_pad_d *eh_landing_pad;
|
||||
typedef struct eh_landing_pad_d *eh_landing_pad;
|
||||
|
||||
extern void using_eh_for_cleanups (void);
|
||||
extern void add_stmt_to_eh_lp (gimple *, int);
|
||||
@@ -30,6 +32,7 @@ extern bool remove_stmt_from_eh_lp (gimple *);
|
||||
extern int lookup_stmt_eh_lp_fn (struct function *, const gimple *);
|
||||
extern int lookup_stmt_eh_lp (const gimple *);
|
||||
extern bool make_eh_dispatch_edges (geh_dispatch *);
|
||||
extern void update_stmt_eh_region(gimple *);
|
||||
extern edge make_eh_edge (gimple *);
|
||||
extern edge redirect_eh_edge (edge, basic_block);
|
||||
extern void redirect_eh_dispatch_edge (geh_dispatch *, edge, basic_block);
|
||||
@@ -38,6 +41,10 @@ extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool,
|
||||
extern bool operation_could_trap_p (enum tree_code, bool, bool, tree);
|
||||
extern bool tree_could_trap_p (tree);
|
||||
extern tree rewrite_to_non_trapping_overflow (tree);
|
||||
extern bool extract_types_for_call (gcall *, vec<tree> *);
|
||||
extern bool stmt_throw_types (function *, gimple *, vec<tree> *);
|
||||
extern bool extract_types_for_resx (gimple *, vec<tree> *);
|
||||
extern bool extract_fun_resx_types (function *, vec<tree> *);
|
||||
extern bool stmt_could_throw_p (function *, gimple *);
|
||||
extern bool stmt_unremovable_because_of_non_call_eh_p (function *, gimple *);
|
||||
extern bool tree_could_throw_p (tree);
|
||||
|
||||
Reference in New Issue
Block a user