diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e449baa16ec..a1b0097cb8d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2005-11-03 Daniel Berlin + + 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 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 index 00000000000..40959effa5e --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr24351-1.C @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +struct adaptor_base { +}; +struct bound_argument { + bound_argument(); +}; +template struct adaptor_functor : public adaptor_base { + explicit adaptor_functor(const T_functor& _A_functor) : functor_(_A_functor) +{ + } + T_functor functor_; + bound_argument bound_; +}; +template struct adapts : public adaptor_base { + explicit adapts(const T_functor& _A_functor) : functor_(_A_functor) { + } + adaptor_functor functor_; +}; +int main() { + adapts > a (adapts(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 index 00000000000..cfc0e4a4cb0 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr24351-2.C @@ -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 index 00000000000..09a3f9462f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr24351-3.C @@ -0,0 +1,101 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +namespace sigc { + template struct type_trait { + typedef T_type& pass; + typedef const T_type& take; + typedef T_type* pointer; + }; + template struct type_trait { + typedef T_type& pass; + }; + template<> struct type_trait { + typedef void pass; + }; + template struct is_base_and_derived { + struct big { + char memory[64]; + }; + static big is_base_class_(...); + static char is_base_class_(typename type_trait::pointer); + static const bool value = sizeof(is_base_class_(reinterpret_cast::pointer>(0))) == sizeof(char); + }; + struct nil; + struct functor_base { + }; + template ::value> struct functor_trait { + typedef typename T_functor::result_type result_type; + typedef T_functor functor_type; + }; + struct adaptor_base : public functor_base { + }; + template ::value> struct deduce_result_type { + typedef typename functor_trait::result_type type; + }; + template struct adaptor_functor + : public adaptor_base { + template struct deduce_result_type { + typedef typename sigc::deduce_result_type::type type; + }; + typedef typename functor_trait::result_type result_type; + template typename deduce_result_type::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 ::value> struct adaptor_trait; + template struct adaptor_trait { + typedef T_functor adaptor_type; + }; + template struct adaptor_trait { + typedef typename functor_trait::functor_type functor_type; + typedef adaptor_functor adaptor_type; + }; + template struct adapts + : public adaptor_base { + typedef typename adaptor_trait::adaptor_type adaptor_type; + explicit adapts(const T_functor& _A_functor) : functor_(_A_functor) { + } + mutable adaptor_type functor_; + }; + template struct unwrap_reference { + typedef T_type type; + }; + template class bound_argument { + public: + bound_argument(const T_type& _A_argument) : visited_(_A_argument) { + } + inline T_type& invoke() { + } + T_type visited_; + }; + template struct bind_functor; + template struct bind_functor<0, T_functor, T_bound, nil,nil,nil,nil,nil,nil> : public adapts { + typedef typename adapts::adaptor_type adaptor_type; + template struct deduce_result_type { + typedef typename adaptor_type::template deduce_result_type::type>::pass, typename type_trait::pass, typename type_trait::pass, typename type_trait::pass, typename type_trait::pass, typename type_trait::pass, typename type_trait::pass>::type type; + }; + typedef typename adaptor_type::result_type result_type; + result_type operator()() { + return this->functor_.template operator()::type>::pass> (bound_.invoke()); + } + template typename deduce_result_type::type operator()(T_arg1 _A_arg1) { + return this->functor_.template operator()::type>::pass, typename type_trait::pass> (bound_.invoke(), _A_arg1); + } + bind_functor(typename type_trait::take _A_func, typename type_trait::take _A_bound) : adapts(_A_func), bound_(_A_bound) { + } + bound_argument bound_; + }; + template inline bind_functor bind(const T_functor& _A_func, T_bound1 _A_b1) { + return bind_functor(_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)(); +} diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 1e1d64d7b9e..cee6502ffea 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -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)