diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e254eec84977b392854d2f3c3efb78ac00914d71..f944bf5920a7e1eafbc97eef0962a8ec177d74e1 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2010-04-27  Martin Jambor  <mjambor@suse.cz>
+
+	PR middle-end/43812
+	* ipa.c (dissolve_same_comdat_group_list): New function.
+	(function_and_variable_visibility): Call
+	dissolve_same_comdat_group_list when comdat group contains external or
+	newly local nodes.
+	* cgraphunit.c (verify_cgraph_node): Verify that same_comdat_group
+	lists are circular and that they contain only DECL_ONE_ONLY nodes.
+
 2010-04-27  Eric Botcazou  <ebotcazou@adacore.com>
 
 	* varasm.c (decode_addr_const): Handle special case of INDIRECT_REF.
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index fcb96b2044c1c965a3373b3d18b5e9459ccc8299..51b4732b45ad4135ccdbb580e85bfbf487d36f10 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -714,6 +714,32 @@ verify_cgraph_node (struct cgraph_node *node)
       error ("double linked list of clones corrupted");
       error_found = true;
     }
+  if (node->same_comdat_group)
+    {
+      struct cgraph_node *n = node->same_comdat_group;
+
+      if (!DECL_ONE_ONLY (node->decl))
+	{
+	  error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
+	  error_found = true;
+	}
+      if (n == node)
+	{
+	  error ("node is alone in a comdat group");
+	  error_found = true;
+	}
+      do
+	{
+	  if (!n->same_comdat_group)
+	    {
+	      error ("same_comdat_group is not a circular list");
+	      error_found = true;
+	      break;
+	    }
+	  n = n->same_comdat_group;
+	}
+      while (n != node);
+    }
 
   if (node->analyzed && gimple_has_body_p (node->decl)
       && !TREE_ASM_WRITTEN (node->decl)
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 3a5ef16d2bea372a06eb8c1056b18fa35070964c..8295357cc0e50c06d478f170ddcb12e622621427 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -355,6 +355,21 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
   return false;
 }
 
+/* Dissolve the same_comdat_group list in which NODE resides.  */
+
+static void
+dissolve_same_comdat_group_list (struct cgraph_node *node)
+{
+  struct cgraph_node *n = node, *next;
+  do
+    {
+      next = n->same_comdat_group;
+      n->same_comdat_group = NULL;
+      n = next;
+    }
+  while (n != node);
+}
+
 /* Mark visibility of all functions.
 
    A local function is one whose calls can occur only in the current
@@ -385,17 +400,17 @@ function_and_variable_visibility (bool whole_program)
 	 and simplifies later passes.  */
       if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
 	{
-	  struct cgraph_node *n = node, *next;
-	  do
-	    {
+#ifdef ENABLE_CHECKING
+	  struct cgraph_node *n;
+
+	  for (n = node->same_comdat_group;
+	       n != node;
+	       n = n->same_comdat_group)
 	      /* If at least one of same comdat group functions is external,
 		 all of them have to be, otherwise it is a front-end bug.  */
 	      gcc_assert (DECL_EXTERNAL (n->decl));
-	      next = n->same_comdat_group;
-	      n->same_comdat_group = NULL;
-	      n = next;
-	    }
-	  while (n != node);
+#endif
+	  dissolve_same_comdat_group_list (node);
 	}
       gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
       	          || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
@@ -411,6 +426,12 @@ function_and_variable_visibility (bool whole_program)
 	{
 	  gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
 	  cgraph_make_decl_local (node->decl);
+	  if (node->same_comdat_group)
+	    /* cgraph_externally_visible_p has already checked all other nodes
+	       in the group and they will all be made local.  We need to
+	       dissolve the group at once so that the predicate does not
+	       segfault though. */
+	    dissolve_same_comdat_group_list (node);
 	}
       node->local.local = (cgraph_only_called_directly_p (node)
 			   && node->analyzed
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 72e61c0e348f57337a6695cadcecd09adaa9f3be..9c0afd60faac78cb26acb12ba30de4d6d907f7f0 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-04-27  Martin Jambor  <mjambor@suse.cz>
+
+	PR middle-end/43812
+	* g++.dg/ipa/pr43812.C: New test.
+
 2010-04-27  Jan Hubicka  <jh@suse.cz>
 
 	* gcc.dg/ipa/iinline-1.c (main): Rename to...
diff --git a/gcc/testsuite/g++.dg/ipa/pr43812.C b/gcc/testsuite/g++.dg/ipa/pr43812.C
new file mode 100644
index 0000000000000000000000000000000000000000..cc46eed6501dc6f09f20680f62a01725fbe9d106
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr43812.C
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fwhole-program -fipa-cp" } */
+
+typedef float scoord_t;
+typedef scoord_t sdist_t;
+typedef sdist_t dist_t;
+template<typename T> class TRay { };
+typedef TRay<dist_t> Ray;
+class BBox { };
+class RenderContext { };
+class RefCounted {
+public:
+    void deref () const {
+        if (--ref_count <= 0) {
+            delete this;
+        }
+    }
+    mutable int ref_count;
+};
+template<class T> class Ref {
+public:
+    ~Ref () {
+        if (obj) obj->deref ();
+    }
+    T *obj;
+};
+class Material : public RefCounted { };
+class Surface {
+public:
+    virtual ~Surface () { }
+    class IsecInfo   { };
+    virtual const IsecInfo *intersect (Ray &ray, RenderContext &context) const;
+    Ref<const Material> material;
+};
+class LocalSurface : public Surface {
+    virtual BBox bbox () const;
+};
+BBox LocalSurface::bbox () const { }