re PR ipa/65610 (Compare debug failure with -g3 -fsanitize=undefined -fno-sanitize=vptr -O3)
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. * g++.dg/ubsan/pr65610.C: New test. From-SVN: r221781
This commit is contained in:
parent
ef4bac7802
commit
00a0ea64ee
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue