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:
Jakub Jelinek 2015-03-30 23:56:02 +02:00 committed by Jakub Jelinek
parent ef4bac7802
commit 00a0ea64ee
7 changed files with 141 additions and 45 deletions

View File

@ -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> 2015-03-27 Jan Hubicka <hubicka@ucw.cz>
PR ipa/65076 PR ipa/65076

View File

@ -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 /* We know that the instance is stored in variable or parameter
(not dynamically allocated) and we want to disprove the fact (not dynamically allocated) and we want to disprove the fact
that it may be in construction at invocation of CALL. 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)) && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
return false; return false;
bool check_clones = !base || is_global_var (base);
for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK; for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
block = BLOCK_SUPERCONTEXT (block)) block = BLOCK_SUPERCONTEXT (block))
if (BLOCK_ABSTRACT_ORIGIN (block) if (tree fn = inlined_polymorphic_ctor_dtor_block_p (block, check_clones))
&& TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL)
{ {
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))); tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (fn)));
if (!outer_type || !types_odr_comparable (type, outer_type)) 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)) block = BLOCK_SUPERCONTEXT (block))
if (BLOCK_ABSTRACT_ORIGIN (block) if (BLOCK_ABSTRACT_ORIGIN (block)
&& TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL)
{ return inlined_polymorphic_ctor_dtor_block_p (block, false);
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 (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE return (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
&& (DECL_CXX_CONSTRUCTOR_P (current_function_decl) && (DECL_CXX_CONSTRUCTOR_P (current_function_decl)
|| DECL_CXX_DESTRUCTOR_P (current_function_decl))); || DECL_CXX_DESTRUCTOR_P (current_function_decl)));

View File

@ -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. */ /* Walk the inline stack and watch out for ctors/dtors. */
for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK; for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
block = BLOCK_SUPERCONTEXT (block)) block = BLOCK_SUPERCONTEXT (block))
if (BLOCK_ABSTRACT_ORIGIN (block) if (inlined_polymorphic_ctor_dtor_block_p (block, false))
&& TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) return true;
{
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;
}
return false; return false;
} }
} }

View File

@ -70,6 +70,7 @@ bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT,
const ipa_polymorphic_call_context &, const ipa_polymorphic_call_context &,
struct cgraph_node *); struct cgraph_node *);
tree method_class_type (const_tree); 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); bool decl_maybe_in_construction_p (tree, tree, gimple, tree);
tree vtable_pointer_value_to_binfo (const_tree); tree vtable_pointer_value_to_binfo (const_tree);
bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *); bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *);

View File

@ -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> 2015-03-30 Marek Polacek <polacek@redhat.com>
PR c++/65398 PR c++/65398

View File

@ -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;
}

View File

@ -76,6 +76,10 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h" #include "diagnostic-core.h"
#include "debug.h" #include "debug.h"
#include "tree-ssa.h" #include "tree-ssa.h"
#include "lto-streamer.h"
#include "ipa-ref.h"
#include "cgraph.h"
#include "ipa-utils.h"
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
static void verify_live_on_entry (tree_live_info_p); static void verify_live_on_entry (tree_live_info_p);
@ -509,12 +513,29 @@ mark_scope_block_unused (tree scope)
done by the inliner. */ done by the inliner. */
static bool static bool
remove_unused_scope_block_p (tree scope) remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
{ {
tree *t, *next; tree *t, *next;
bool unused = !TREE_USED (scope); bool unused = !TREE_USED (scope);
int nsubblocks = 0; 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) for (t = &BLOCK_VARS (scope); *t; t = next)
{ {
next = &DECL_CHAIN (*t); next = &DECL_CHAIN (*t);
@ -594,7 +615,7 @@ remove_unused_scope_block_p (tree scope)
} }
for (t = &BLOCK_SUBBLOCKS (scope); *t ;) 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)) if (BLOCK_SUBBLOCKS (*t))
{ {
@ -959,7 +980,7 @@ remove_unused_locals (void)
cfun->local_decls->truncate (dstidx); 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 (); clear_unused_block_pointer ();
BITMAP_FREE (usedvars); BITMAP_FREE (usedvars);