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>
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
(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)));

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. */
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;
}
}

View File

@ -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 *);

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>
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 "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);