re PR ipa/65610 (Compare debug failure with -g3 -fsanitize=undefined -fno-sanitize...
authorJakub Jelinek <jakub@redhat.com>
Mon, 30 Mar 2015 21:56:02 +0000 (23:56 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 30 Mar 2015 21:56:02 +0000 (23:56 +0200)
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

gcc/ChangeLog
gcc/ipa-polymorphic-call.c
gcc/ipa-prop.c
gcc/ipa-utils.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/pr65610.C [new file with mode: 0644]
gcc/tree-ssa-live.c

index e3d2a3d2af6b88848be8e509a5d02de2d838f2d2..242eb5075790568322985205073c5fc91403fae3 100644 (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
index 90303f1bcfc3fd40d05f8e39d2dcbe2961e7b110..e0fd31ad52339a81a5a58304060ae64a331f5f2f 100644 (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)));
index cfd9c16ed9c17c6ff0fc181379d25d8bac088367..89a4623e0c2884e10eccf08a447efc2147717df7 100644 (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;
        }
     }
index d302456ae94568e42307006768460ff2de42304e..0cf654163f7f55176a0377efdd1e2c64ebf6dd1c 100644 (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 *);
index d792b9f95376b6db09cd6557d30d6b3d825c7aaa..708d8c65ad46c28b789a2866c79e945c6085b892 100644 (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
diff --git a/gcc/testsuite/g++.dg/ubsan/pr65610.C b/gcc/testsuite/g++.dg/ubsan/pr65610.C
new file mode 100644 (file)
index 0000000..ced59a8
--- /dev/null
@@ -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;
+}
index e0c4266938fde4e6cd64627dee643dd5fb862e4a..df902292596d9b153338a8d21fee32e549b73420 100644 (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);