diff options
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/ipa-polymorphic-call.c | 65 | ||||
-rw-r--r-- | gcc/ipa-prop.c | 14 | ||||
-rw-r--r-- | gcc/ipa-utils.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ubsan/pr65610.C | 57 | ||||
-rw-r--r-- | gcc/tree-ssa-live.c | 27 |
7 files changed, 141 insertions, 45 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e3d2a3d..242eb50 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2015-03-30 Jakub Jelinek <jakub@redhat.com> + + PR ipa/65610 + * ipa-utils.h (inlined_polymorphic_ctor_dtor_block_p): Declare. + * ipa-polymorphic-call.c (inlined_polymorphic_ctor_dtor_block_p): New + function. + (decl_maybe_in_construction_p, noncall_stmt_may_be_vtbl_ptr_store): + Use it. + * ipa-prop.c (param_type_may_change_p): Likewise. + * tree-ssa-live.c: Include ipa-utils.h and its dependencies. + (remove_unused_scope_block_p): Add in_ctor_dtor_block + argument. Before inlining, preserve + inlined_polymorphic_ctor_dtor_block_p blocks and the outermost block + with FUNCTION_DECL BLOCK_ABSTRACT_ORIGIN inside of them. Adjust + recursive calls. + (remove_unused_locals): Adjust remove_unused_scope_block_p caller. + 2015-03-27 Jan Hubicka <hubicka@ucw.cz> PR ipa/65076 diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c index 90303f1..e0fd31a 100644 --- a/gcc/ipa-polymorphic-call.c +++ b/gcc/ipa-polymorphic-call.c @@ -513,6 +513,38 @@ contains_type_p (tree outer_type, HOST_WIDE_INT offset, } +/* Return a FUNCTION_DECL if BLOCK represents a constructor or destructor. + If CHECK_CLONES is true, also check for clones of ctor/dtors. */ + +tree +inlined_polymorphic_ctor_dtor_block_p (tree block, bool check_clones) +{ + tree fn = BLOCK_ABSTRACT_ORIGIN (block); + if (fn == NULL || TREE_CODE (fn) != FUNCTION_DECL) + return NULL_TREE; + + if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn))) + { + if (!check_clones) + return NULL_TREE; + + /* Watch for clones where we constant propagated the first + argument (pointer to the instance). */ + fn = DECL_ABSTRACT_ORIGIN (fn); + if (!fn + || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn))) + return NULL_TREE; + } + + if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) + return NULL_TREE; + + return fn; +} + + /* We know that the instance is stored in variable or parameter (not dynamically allocated) and we want to disprove the fact that it may be in construction at invocation of CALL. @@ -550,30 +582,11 @@ decl_maybe_in_construction_p (tree base, tree outer_type, && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST)) return false; + bool check_clones = !base || is_global_var (base); for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK; block = BLOCK_SUPERCONTEXT (block)) - if (BLOCK_ABSTRACT_ORIGIN (block) - && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) + if (tree fn = inlined_polymorphic_ctor_dtor_block_p (block, check_clones)) { - tree fn = BLOCK_ABSTRACT_ORIGIN (block); - - if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE - || (!DECL_CXX_CONSTRUCTOR_P (fn) - && !DECL_CXX_DESTRUCTOR_P (fn))) - { - /* Watch for clones where we constant propagated the first - argument (pointer to the instance). */ - fn = DECL_ABSTRACT_ORIGIN (fn); - if (!fn - || (base && !is_global_var (base)) - || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE - || (!DECL_CXX_CONSTRUCTOR_P (fn) - && !DECL_CXX_DESTRUCTOR_P (fn))) - continue; - } - if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) - continue; - tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (fn))); if (!outer_type || !types_odr_comparable (type, outer_type)) @@ -1163,15 +1176,7 @@ noncall_stmt_may_be_vtbl_ptr_store (gimple stmt) block = BLOCK_SUPERCONTEXT (block)) if (BLOCK_ABSTRACT_ORIGIN (block) && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) - { - tree fn = BLOCK_ABSTRACT_ORIGIN (block); - - if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) - return false; - return (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE - && (DECL_CXX_CONSTRUCTOR_P (fn) - || DECL_CXX_DESTRUCTOR_P (fn))); - } + return inlined_polymorphic_ctor_dtor_block_p (block, false); return (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE && (DECL_CXX_CONSTRUCTOR_P (current_function_decl) || DECL_CXX_DESTRUCTOR_P (current_function_decl))); diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index cfd9c16..89a4623 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -715,18 +715,8 @@ param_type_may_change_p (tree function, tree arg, gimple call) /* Walk the inline stack and watch out for ctors/dtors. */ for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK; block = BLOCK_SUPERCONTEXT (block)) - if (BLOCK_ABSTRACT_ORIGIN (block) - && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) - { - tree fn = BLOCK_ABSTRACT_ORIGIN (block); - - if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) - continue; - if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE - && (DECL_CXX_CONSTRUCTOR_P (fn) - || DECL_CXX_DESTRUCTOR_P (fn))) - return true; - } + if (inlined_polymorphic_ctor_dtor_block_p (block, false)) + return true; return false; } } diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index d302456..0cf6541 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -70,6 +70,7 @@ bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT, const ipa_polymorphic_call_context &, struct cgraph_node *); tree method_class_type (const_tree); +tree inlined_polymorphic_ctor_dtor_block_p (tree, bool); bool decl_maybe_in_construction_p (tree, tree, gimple, tree); tree vtable_pointer_value_to_binfo (const_tree); bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d792b9f..708d8c6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-03-30 Jakub Jelinek <jakub@redhat.com> + + PR ipa/65610 + * g++.dg/ubsan/pr65610.C: New test. + 2015-03-30 Marek Polacek <polacek@redhat.com> PR c++/65398 diff --git a/gcc/testsuite/g++.dg/ubsan/pr65610.C b/gcc/testsuite/g++.dg/ubsan/pr65610.C new file mode 100644 index 0000000..ced59a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/pr65610.C @@ -0,0 +1,57 @@ +// PR ipa/65610 +// { dg-do compile } +// { dg-options "-std=c++11 -fsanitize=undefined -fno-sanitize=vptr -fcompare-debug" } + +class A; +class B {}; +enum C { D }; +class E; +class F; +class G; +class H +{ + F m1 (const A &t) const; + G m2 () const; +}; +class G {}; +template <class S, class T> +class I; +template <class S, class T> +class J +{ + friend class I <S,T>; + J <S,T> *j; +}; +template <class S, class T> +struct I +{ + virtual ~I (); + virtual void m3 (void *p) {} + J <S,T> *i; + void m4 (J <S,T>*& t); +}; +template <class S, class T> +void I <S,T>::m4 (J <S,T> * &t) +{ + m4 (t->j); + m3 (t); +} +template <class S, class T> +I <S,T>::~I () +{ + m4 (i); +} +struct F +{ + explicit inline F (C v); + inline ~F (); + I <B, E> f; +}; +inline F::F (C v) {} +inline F::~F () {} +F H::m1 (const A &t) const +{ + F q (D); + G r = m2 (); + return q; +} diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index e0c42669..df90229 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -76,6 +76,10 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "debug.h" #include "tree-ssa.h" +#include "lto-streamer.h" +#include "ipa-ref.h" +#include "cgraph.h" +#include "ipa-utils.h" #ifdef ENABLE_CHECKING static void verify_live_on_entry (tree_live_info_p); @@ -509,12 +513,29 @@ mark_scope_block_unused (tree scope) done by the inliner. */ static bool -remove_unused_scope_block_p (tree scope) +remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block) { tree *t, *next; bool unused = !TREE_USED (scope); int nsubblocks = 0; + /* For ipa-polymorphic-call.c purposes, preserve blocks: + 1) with BLOCK_ABSTRACT_ORIGIN of a ctor/dtor or their clones */ + if (inlined_polymorphic_ctor_dtor_block_p (scope, true)) + { + in_ctor_dtor_block = true; + unused = false; + } + /* 2) inside such blocks, the outermost block with BLOCK_ABSTRACT_ORIGIN + being a FUNCTION_DECL. */ + else if (in_ctor_dtor_block + && BLOCK_ABSTRACT_ORIGIN (scope) + && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (scope)) == FUNCTION_DECL) + { + in_ctor_dtor_block = false; + unused = false; + } + for (t = &BLOCK_VARS (scope); *t; t = next) { next = &DECL_CHAIN (*t); @@ -594,7 +615,7 @@ remove_unused_scope_block_p (tree scope) } for (t = &BLOCK_SUBBLOCKS (scope); *t ;) - if (remove_unused_scope_block_p (*t)) + if (remove_unused_scope_block_p (*t, in_ctor_dtor_block)) { if (BLOCK_SUBBLOCKS (*t)) { @@ -959,7 +980,7 @@ remove_unused_locals (void) cfun->local_decls->truncate (dstidx); } - remove_unused_scope_block_p (DECL_INITIAL (current_function_decl)); + remove_unused_scope_block_p (DECL_INITIAL (current_function_decl), false); clear_unused_block_pointer (); BITMAP_FREE (usedvars); |