re PR tree-optimization/24351 (ICE in do_simple_structure_copy with some C++ code)
authorDaniel Berlin <dberlin@dberlin.org>
Thu, 3 Nov 2005 15:39:48 +0000 (15:39 +0000)
committerDaniel Berlin <dberlin@gcc.gnu.org>
Thu, 3 Nov 2005 15:39:48 +0000 (15:39 +0000)
2005-11-03  Daniel Berlin  <dberlin@dberlin.org>

Fix PR tree-optimization/24351

* tree-ssa-structalias.c (struct variable_info): Add
collapsed_into.
(get_varinfo_fc): New function to follow collapsing.
(new_var_info): Set collapsed_to to NULL.
(dump_constraint): Follow collapsing.
(build_constraint_graph): Handle collapsing.
(do_simple_structure_copy): Return false if something bad
happened.
(collapse_rest_of_var): New function.
(do_structure_copy): Collapse if do_simple_structure_copy returns
false.

From-SVN: r106437

gcc/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr24351-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tree-ssa/pr24351-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tree-ssa/pr24351-3.C [new file with mode: 0644]
gcc/tree-ssa-structalias.c

index e449baa16ecc7c4fbe6bf445142873583660aab2..a1b0097cb8dcb2e1ef4f84cb47b5109150a79143 100644 (file)
@@ -1,3 +1,19 @@
+2005-11-03  Daniel Berlin  <dberlin@dberlin.org>
+
+       Fix PR tree-optimization/24351
+
+       * tree-ssa-structalias.c (struct variable_info): Add
+       collapsed_into.
+       (get_varinfo_fc): New function to follow collapsing.
+       (new_var_info): Set collapsed_to to NULL.
+       (dump_constraint): Follow collapsing.
+       (build_constraint_graph): Handle collapsing.
+       (do_simple_structure_copy): Return false if something bad
+       happened.
+       (collapse_rest_of_var): New function.
+       (do_structure_copy): Collapse if do_simple_structure_copy returns
+       false.
+       
 2005-11-03  Andrew Pinski  <pinskia@physics.uc.edu>
 
        PR middle-end/24589
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr24351-1.C b/gcc/testsuite/g++.dg/tree-ssa/pr24351-1.C
new file mode 100644 (file)
index 0000000..40959ef
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+struct adaptor_base {
+};
+struct bound_argument {
+  bound_argument();
+};
+template <class T_functor> struct adaptor_functor : public adaptor_base {
+  explicit adaptor_functor(const T_functor& _A_functor) : functor_(_A_functor)
+{
+  }
+  T_functor functor_;
+  bound_argument bound_;
+};
+template <class T_functor> struct adapts : public adaptor_base {
+  explicit adapts(const T_functor& _A_functor) : functor_(_A_functor) {
+  }
+  adaptor_functor<T_functor> functor_;
+};
+int main() {
+  adapts<adapts<int> > a (adapts<int>(1));
+}
+
+
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr24351-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr24351-2.C
new file mode 100644 (file)
index 0000000..cfc0e4a
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+struct adaptor_base {};
+struct bound_argument {
+  bound_argument();
+};
+struct adaptor_functorint : public adaptor_base {};
+struct adaptsint : public adaptor_base {
+  adaptsint(const int& _A_functor);
+  adaptor_functorint functor_;
+};
+struct adaptor_functor_adaptsint {
+  adaptor_functor_adaptsint(const adaptsint& _A_functor) : functor_(_A_functor)
+  {}
+  adaptsint functor_;
+  bound_argument bound_;
+};
+struct adapts_adaptsint {
+  adapts_adaptsint(const adaptsint& _A_functor) : functor_(_A_functor)
+  {}
+  adaptor_functor_adaptsint functor_;
+};
+int main() {
+  adapts_adaptsint a (adaptsint(1));
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr24351-3.C b/gcc/testsuite/g++.dg/tree-ssa/pr24351-3.C
new file mode 100644 (file)
index 0000000..09a3f94
--- /dev/null
@@ -0,0 +1,101 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+namespace sigc {
+    template <class T_type>     struct type_trait     {
+       typedef T_type& pass;
+       typedef const T_type& take;
+       typedef T_type* pointer;
+    };
+    template <class T_type>     struct type_trait<T_type&>     {
+       typedef T_type& pass;
+    };
+    template<>     struct type_trait<void>     {
+       typedef void pass;
+    };
+    template <class T_base, class T_derived>     struct is_base_and_derived     {
+       struct big {
+           char memory[64];
+       };
+       static big is_base_class_(...);
+       static char is_base_class_(typename type_trait<T_base>::pointer);
+       static const bool value = sizeof(is_base_class_(reinterpret_cast<typename type_trait<T_derived>::pointer>(0))) == sizeof(char);
+    };
+    struct nil;
+    struct functor_base {
+    };
+    template <class T_functor, bool I_derives_functor_base=is_base_and_derived<functor_base,T_functor>::value>     struct functor_trait     {
+       typedef typename T_functor::result_type result_type;
+       typedef T_functor functor_type;
+    };
+    struct adaptor_base : public functor_base {
+    };
+    template <class T_functor, class T_arg1=void,class T_arg2=void,class T_arg3=void,class T_arg4=void,class T_arg5=void,class T_arg6=void,class T_arg7=void, bool I_derives_adaptor_base=is_base_and_derived<adaptor_base,T_functor>::value>     struct deduce_result_type     {
+       typedef typename functor_trait<T_functor>::result_type type;
+    };
+    template <class T_functor>     struct adaptor_functor
+       : public adaptor_base     {
+       template <class T_arg1=void,class T_arg2=void,class T_arg3=void,class T_arg4=void,class T_arg5=void,class T_arg6=void,class T_arg7=void>        struct deduce_result_type       {
+           typedef typename sigc::deduce_result_type<T_functor, T_arg1,T_arg2,T_arg3,T_arg4,T_arg5,T_arg6,T_arg7>::type type;
+       };
+       typedef typename functor_trait<T_functor>::result_type result_type;
+       template <class T_arg1,class T_arg2>    typename deduce_result_type<T_arg1,T_arg2>::type operator()(T_arg1 _A_arg1,T_arg2 _A_arg2) const        {
+           return functor_(_A_arg1,_A_arg2);
+       }
+       explicit adaptor_functor(const T_functor& _A_functor) : functor_(_A_functor) {
+       }
+       mutable T_functor functor_;
+    };
+    template <class T_functor, bool I_isadaptor = is_base_and_derived<adaptor_base, T_functor>::value>     struct adaptor_trait;
+    template <class T_functor>     struct adaptor_trait<T_functor, true>     {
+       typedef T_functor adaptor_type;
+    };
+    template <class T_functor>     struct adaptor_trait<T_functor, false>     {
+       typedef typename functor_trait<T_functor>::functor_type functor_type;
+       typedef adaptor_functor<functor_type> adaptor_type;
+    };
+    template <class T_functor>     struct adapts
+       : public adaptor_base     {
+       typedef typename adaptor_trait<T_functor>::adaptor_type adaptor_type;
+       explicit adapts(const T_functor& _A_functor) : functor_(_A_functor) {
+       }
+       mutable adaptor_type functor_;
+    };
+    template <class T_type>     struct unwrap_reference     {
+       typedef T_type type;
+    };
+    template <class T_type>     class bound_argument     {
+    public:
+       bound_argument(const T_type& _A_argument) : visited_(_A_argument) {
+       }
+       inline T_type& invoke() {
+       }
+       T_type visited_;
+    };
+    template <int I_location, class T_functor, class T_type1=nil,class T_type2=nil,class T_type3=nil,class T_type4=nil,class T_type5=nil,class T_type6=nil,class T_type7=nil>     struct bind_functor;
+    template <class T_functor, class T_bound>     struct bind_functor<0, T_functor, T_bound, nil,nil,nil,nil,nil,nil> : public adapts<T_functor>     {
+       typedef typename adapts<T_functor>::adaptor_type adaptor_type;
+       template <class T_arg1=void,class T_arg2=void,class T_arg3=void,class T_arg4=void,class T_arg5=void,class T_arg6=void,class T_arg7=void>        struct deduce_result_type       {
+           typedef typename adaptor_type::template deduce_result_type<typename type_trait<typename unwrap_reference<T_bound>::type>::pass, typename type_trait<T_arg1>::pass, typename type_trait<T_arg2>::pass, typename type_trait<T_arg3>::pass, typename type_trait<T_arg4>::pass, typename type_trait<T_arg5>::pass, typename type_trait<T_arg6>::pass>::type type;
+       };
+       typedef typename adaptor_type::result_type result_type;
+       result_type operator()()        {
+           return this->functor_.template operator()<typename type_trait<typename unwrap_reference<T_bound>::type>::pass> (bound_.invoke());
+       }
+       template <class T_arg1>         typename deduce_result_type<T_arg1>::type operator()(T_arg1 _A_arg1)    {
+           return this->functor_.template operator()<typename type_trait<typename unwrap_reference<T_bound>::type>::pass, typename type_trait<T_arg1>::pass>         (bound_.invoke(), _A_arg1);
+       }
+       bind_functor(typename type_trait<T_functor>::take _A_func, typename type_trait<T_bound>::take _A_bound) : adapts<T_functor>(_A_func), bound_(_A_bound) {
+       }
+       bound_argument<T_bound> bound_;
+    };
+    template <int I_location, class T_bound1, class T_functor> inline bind_functor<I_location, T_functor, T_bound1>     bind(const T_functor& _A_func, T_bound1 _A_b1)     {
+       return bind_functor<I_location, T_functor, T_bound1>(_A_func, _A_b1);
+    };
+}
+struct foo {
+    typedef int result_type;
+    int operator()(int i, int j);
+};
+int main() {
+    sigc::bind<0>(sigc::bind<0>(foo(),7),8)();
+}
index 1e1d64d7b9e9b1e2980d9a2fdcea11b22b0c9ceb..cee6502ffea40ff41ae1ee6c00504ee0799316af 100644 (file)
@@ -239,6 +239,11 @@ struct variable_info
   /* Vector of complex constraints for this node.  Complex
      constraints are those involving dereferences.  */
   VEC(constraint_t,heap) *complex;
+  
+  /* Variable id this was collapsed to due to type unsafety.
+     This should be unused completely after build_constraint_graph, or
+     something is broken.  */
+  struct variable_info *collapsed_to;
 };
 typedef struct variable_info *varinfo_t;
 
@@ -258,11 +263,23 @@ static VEC(varinfo_t,heap) *varmap;
 /* Return the varmap element N */
 
 static inline varinfo_t
-get_varinfo(unsigned int n)
+get_varinfo (unsigned int n)
 {
   return VEC_index(varinfo_t, varmap, n);
 }
 
+/* Return the varmap element N, following the collapsed_to link.  */
+
+static inline varinfo_t
+get_varinfo_fc (unsigned int n)
+{
+  varinfo_t v = VEC_index(varinfo_t, varmap, n);
+
+  if (v->collapsed_to)
+    return v->collapsed_to;
+  return v;
+}
+
 /* Variable that represents the unknown pointer.  */
 static varinfo_t var_anything;
 static tree anything_tree;
@@ -316,6 +333,7 @@ new_var_info (tree t, unsigned int id, const char *name, unsigned int node)
   bitmap_clear (ret->variables);
   ret->complex = NULL;
   ret->next = NULL;
+  ret->collapsed_to = NULL;
   return ret;
 }
 
@@ -429,7 +447,7 @@ dump_constraint (FILE *file, constraint_t c)
     fprintf (file, "&");
   else if (c->lhs.type == DEREF)
     fprintf (file, "*");  
-  fprintf (file, "%s", get_varinfo (c->lhs.var)->name);
+  fprintf (file, "%s", get_varinfo_fc (c->lhs.var)->name);
   if (c->lhs.offset != 0)
     fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->lhs.offset);
   fprintf (file, " = ");
@@ -437,7 +455,7 @@ dump_constraint (FILE *file, constraint_t c)
     fprintf (file, "&");
   else if (c->rhs.type == DEREF)
     fprintf (file, "*");
-  fprintf (file, "%s", get_varinfo (c->rhs.var)->name);
+  fprintf (file, "%s", get_varinfo_fc (c->rhs.var)->name);
   if (c->rhs.offset != 0)
     fprintf (file, " + " HOST_WIDE_INT_PRINT_DEC, c->rhs.offset);
   fprintf (file, "\n");
@@ -982,33 +1000,36 @@ build_constraint_graph (void)
     {
       struct constraint_expr lhs = c->lhs;
       struct constraint_expr rhs = c->rhs;
+      unsigned int lhsvar = get_varinfo_fc (lhs.var)->id;
+      unsigned int rhsvar = get_varinfo_fc (rhs.var)->id;
+
       if (lhs.type == DEREF)
        {
          /* *x = y or *x = &y (complex) */
-         if (rhs.type == ADDRESSOF || rhs.var > anything_id)
-           insert_into_complex (lhs.var, c);
+         if (rhs.type == ADDRESSOF || rhsvar > anything_id)
+           insert_into_complex (lhsvar, c);
        }
       else if (rhs.type == DEREF)
        {
          /* !special var= *y */
-         if (!(get_varinfo (lhs.var)->is_special_var))
-           insert_into_complex (rhs.var, c);
+         if (!(get_varinfo (lhsvar)->is_special_var))
+           insert_into_complex (rhsvar, c);
        }
       else if (rhs.type == ADDRESSOF)
        {
          /* x = &y */
-         bitmap_set_bit (get_varinfo (lhs.var)->solution, rhs.var);
+         bitmap_set_bit (get_varinfo (lhsvar)->solution, rhsvar);
        }
-      else if (lhs.var > anything_id)
+      else if (lhsvar > anything_id)
        {
          /* Ignore 0 weighted self edges, as they can't possibly contribute
             anything */
-         if (lhs.var != rhs.var || rhs.offset != 0 || lhs.offset != 0)
+         if (lhsvar != rhsvar || rhs.offset != 0 || lhs.offset != 0)
            {
              
              struct constraint_edge edge;
-             edge.src = lhs.var;
-             edge.dest = rhs.var;
+             edge.src = lhsvar;
+             edge.dest = rhsvar;
              /* x = y (simple) */
              add_graph_edge (graph, edge);
              bitmap_set_bit (get_graph_weights (graph, edge),
@@ -2300,9 +2321,12 @@ get_constraint_for (tree t, bool *need_anyoffset)
    For each field of the lhs variable (lhsfield)
      For each field of the rhs variable at lhsfield.offset (rhsfield)
        add the constraint lhsfield = rhsfield
-*/
 
-static void
+   If we fail due to some kind of type unsafety or other thing we
+   can't handle, return false.  We expect the caller to collapse the
+   variable in that case.  */
+
+static bool
 do_simple_structure_copy (const struct constraint_expr lhs,
                          const struct constraint_expr rhs,
                          const unsigned HOST_WIDE_INT size)
@@ -2322,9 +2346,12 @@ do_simple_structure_copy (const struct constraint_expr lhs,
       q = get_varinfo (temprhs.var);
       fieldoffset = p->offset - pstart;
       q = first_vi_for_offset (q, q->offset + fieldoffset);
+      if (!q)
+       return false;
       temprhs.var = q->id;
       process_constraint (new_constraint (templhs, temprhs));
     }
+  return true;
 }
 
 
@@ -2406,6 +2433,32 @@ do_lhs_deref_structure_copy (const struct constraint_expr lhs,
     }
 }
 
+/* Sometimes, frontends like to give us bad type information.  This
+   function will collapse all the fields from VAR to the end of VAR,
+   into VAR, so that we treat those fields as a single variable. 
+   We return the variable they were collapsed into.  */
+
+static unsigned int
+collapse_rest_of_var (unsigned int var)
+{
+  varinfo_t currvar = get_varinfo (var);
+  varinfo_t field;
+
+  for (field = currvar->next; field; field = field->next)
+    {
+      if (dump_file)
+       fprintf (dump_file, "Type safety: Collapsing var %s into %s\n", 
+                field->name, currvar->name);
+      
+      gcc_assert (!field->collapsed_to);
+      field->collapsed_to = currvar;
+    }
+
+  currvar->next = NULL;
+  currvar->size = currvar->fullsize - currvar->offset;
+  
+  return currvar->id;
+}
 
 /* Handle aggregate copies by expanding into copies of the respective
    fields of the structures.  */
@@ -2492,7 +2545,18 @@ do_structure_copy (tree lhsop, tree rhsop)
 
   
       if (rhs.type == SCALAR && lhs.type == SCALAR)  
-       do_simple_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+       {
+         if (!do_simple_structure_copy (lhs, rhs, MIN (lhssize, rhssize)))
+           {         
+             lhs.var = collapse_rest_of_var (lhs.var);
+             rhs.var = collapse_rest_of_var (rhs.var);
+             lhs.offset = 0;
+             rhs.offset = 0;
+             lhs.type = SCALAR;
+             rhs.type = SCALAR;
+             process_constraint (new_constraint (lhs, rhs));
+           }
+       }
       else if (lhs.type != DEREF && rhs.type == DEREF)
        do_rhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
       else if (lhs.type == DEREF && rhs.type != DEREF)