diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e449baa16ecc7c4fbe6bf445142873583660aab2..a1b0097cb8dcb2e1ef4f84cb47b5109150a79143 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
index 0000000000000000000000000000000000000000..40959effa5e50acea9d58f5075fdaa64777df901
--- /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 <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
index 0000000000000000000000000000000000000000..cfc0e4a4cb0b7322b50bbbe7c63edb26254e5577
--- /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 0000000000000000000000000000000000000000..09a3f9462f35e3d573e710018ee6545e6855152a
--- /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 <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)();
+}
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 1e1d64d7b9e9b1e2980d9a2fdcea11b22b0c9ceb..cee6502ffea40ff41ae1ee6c00504ee0799316af 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)