Index: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	(revision 218024)
+++ gcc/cgraph.c	(working copy)
@@ -2193,15 +2193,16 @@ cgraph_node::can_be_local_p (void)
 						NULL, true));
 }
 
-/* Call calback on cgraph_node, thunks and aliases associated to cgraph_node.
+/* Call callback on cgraph_node, thunks and aliases associated to cgraph_node.
    When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
-
+   skipped.  When EXCLUDE_VIRTUAL_THUNKS is true, virtual thunks are
+   skipped.  */
 bool
 cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
 						   (cgraph_node *, void *),
 						 void *data,
-						 bool include_overwritable)
+						 bool include_overwritable,
+						 bool exclude_virtual_thunks)
 {
   cgraph_edge *e;
   ipa_ref *ref;
@@ -2211,9 +2212,12 @@ cgraph_node::call_for_symbol_thunks_and_aliases (b
   for (e = callers; e; e = e->next_caller)
     if (e->caller->thunk.thunk_p
 	&& (include_overwritable
-	    || e->caller->get_availability () > AVAIL_INTERPOSABLE))
+	    || e->caller->get_availability () > AVAIL_INTERPOSABLE)
+	&& !(exclude_virtual_thunks
+	     && e->caller->thunk.virtual_offset_p))
       if (e->caller->call_for_symbol_thunks_and_aliases (callback, data,
-						       include_overwritable))
+						       include_overwritable,
+						       exclude_virtual_thunks))
 	return true;
 
   FOR_EACH_ALIAS (this, ref)
@@ -2222,15 +2226,16 @@ cgraph_node::call_for_symbol_thunks_and_aliases (b
       if (include_overwritable
 	  || alias->get_availability () > AVAIL_INTERPOSABLE)
 	if (alias->call_for_symbol_thunks_and_aliases (callback, data,
-						     include_overwritable))
+						     include_overwritable,
+						     exclude_virtual_thunks))
 	  return true;
     }
   return false;
 }
 
-/* Call calback on function and aliases associated to the function.
+/* Call callback on function and aliases associated to the function.
    When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
+   skipped.  */
 
 bool
 cgraph_node::call_for_symbol_and_aliases (bool (*callback) (cgraph_node *,
@@ -2338,7 +2343,7 @@ cgraph_node::set_const_flag (bool readonly, bool l
 {
   call_for_symbol_thunks_and_aliases (cgraph_set_const_flag_1,
 				    (void *)(size_t)(readonly + (int)looping * 2),
-				      false);
+				    false, true);
 }
 
 /* Worker to set pure flag.  */
@@ -2368,7 +2373,7 @@ cgraph_node::set_pure_flag (bool pure, bool loopin
 {
   call_for_symbol_thunks_and_aliases (cgraph_set_pure_flag_1,
 				    (void *)(size_t)(pure + (int)looping * 2),
-				    false);
+				    false, true);
 }
 
 /* Return true when cgraph_node can not return or throw and thus
@@ -3118,30 +3123,52 @@ cgraph_node::verify_cgraph_nodes (void)
 }
 
 /* Walk the alias chain to return the function cgraph_node is alias of.
-   Walk through thunk, too.
+   Walk through thunks, too.
    When AVAILABILITY is non-NULL, get minimal availability in the chain.  */
 
 cgraph_node *
 cgraph_node::function_symbol (enum availability *availability)
 {
-  cgraph_node *node = this;
+  cgraph_node *node = ultimate_alias_target (availability);
 
-  do
+  while (node->thunk.thunk_p)
     {
+      node = node->callees->callee;
+      if (availability)
+	{
+	  enum availability a;
+	  a = node->get_availability ();
+	  if (a < *availability)
+	    *availability = a;
+	}
       node = node->ultimate_alias_target (availability);
-      if (node->thunk.thunk_p)
+    }
+  return node;
+}
+
+/* Walk the alias chain to return the function cgraph_node is alias of.
+   Walk through non virtual thunks, too.  Thus we return either a function
+   or a virtual thunk node.
+   When AVAILABILITY is non-NULL, get minimal availability in the chain.  */
+
+cgraph_node *
+cgraph_node::function_or_virtual_thunk_symbol
+				(enum availability *availability)
+{
+  cgraph_node *node = ultimate_alias_target (availability);
+
+  while (node->thunk.thunk_p && !node->thunk.virtual_offset_p)
+    {
+      node = node->callees->callee;
+      if (availability)
 	{
-	  node = node->callees->callee;
-	  if (availability)
-	    {
-	      enum availability a;
-	      a = node->get_availability ();
-	      if (a < *availability)
-		*availability = a;
-	    }
-	  node = node->ultimate_alias_target (availability);
+	  enum availability a;
+	  a = node->get_availability ();
+	  if (a < *availability)
+	    *availability = a;
 	}
-    } while (node && node->thunk.thunk_p);
+      node = node->ultimate_alias_target (availability);
+    }
   return node;
 }
 
Index: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	(revision 218024)
+++ gcc/cgraph.h	(working copy)
@@ -254,9 +254,9 @@ class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL")
      body aliases.  */
   void fixup_same_cpp_alias_visibility (symtab_node *target);
 
-  /* Call calback on symtab node and aliases associated to this node.
+  /* Call callback on symtab node and aliases associated to this node.
      When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-     skipped. */
+     skipped.  */
   bool call_for_symbol_and_aliases (bool (*callback) (symtab_node *, void *),
 				  void *data,
 				  bool include_overwrite);
@@ -793,6 +793,13 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node
      When AVAILABILITY is non-NULL, get minimal availability in the chain.  */
   cgraph_node *function_symbol (enum availability *avail = NULL);
 
+  /* Walk the alias chain to return the function cgraph_node is alias of.
+     Walk through non virtual thunks, too.  Thus we return either a function
+     or a virtual thunk node.
+     When AVAILABILITY is non-NULL, get minimal availability in the chain.  */
+  cgraph_node *function_or_virtual_thunk_symbol
+				(enum availability *avail = NULL);
+
   /* Create node representing clone of N executed COUNT times.  Decrease
      the execution counts from original node too.
      The new clone will have decl set to DECL that may or may not be the same
@@ -1015,7 +1022,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node
      if any to PURE.  */
   void set_pure_flag (bool pure, bool looping);
 
-  /* Call calback on function and aliases associated to the function.
+  /* Call callback on function and aliases associated to the function.
      When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
      skipped. */
 
@@ -1023,13 +1030,15 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node
 						      void *),
 				    void *data, bool include_overwritable);
 
-  /* Call calback on cgraph_node, thunks and aliases associated to NODE.
+  /* Call callback on cgraph_node, thunks and aliases associated to NODE.
      When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+     skipped.  When EXCLUDE_VIRTUAL_THUNKS is true, virtual thunks are
      skipped.  */
   bool call_for_symbol_thunks_and_aliases (bool (*callback) (cgraph_node *node,
-							   void *data),
-					 void *data,
-					 bool include_overwritable);
+							     void *data),
+					   void *data,
+					   bool include_overwritable,
+					   bool exclude_virtual_thunks = false);
 
   /* Likewise indicate that a node is needed, i.e. reachable via some
      external means.  */
Index: gcc/ipa-pure-const.c
===================================================================
--- gcc/ipa-pure-const.c	(revision 218024)
+++ gcc/ipa-pure-const.c	(working copy)
@@ -806,6 +806,8 @@ analyze_function (struct cgraph_node *fn, bool ipa
     {
       /* Thunk gets propagated through, so nothing interesting happens.  */
       gcc_assert (ipa);
+      if (fn->thunk.thunk_p && fn->thunk.virtual_offset_p)
+	l->pure_const_state = IPA_NEITHER;
       return l;
     }
 
@@ -1247,7 +1249,8 @@ propagate_pure_const (void)
 	  for (e = w->callees; e; e = e->next_callee)
 	    {
 	      enum availability avail;
-	      struct cgraph_node *y = e->callee->function_symbol (&avail);
+	      struct cgraph_node *y = e->callee->
+				function_or_virtual_thunk_symbol (&avail);
 	      enum pure_const_state_e edge_state = IPA_CONST;
 	      bool edge_looping = false;
 
@@ -1387,7 +1390,8 @@ propagate_pure_const (void)
 	  for (e = w->callees; e && !can_free; e = e->next_callee)
 	    {
 	      enum availability avail;
-	      struct cgraph_node *y = e->callee->function_symbol (&avail);
+	      struct cgraph_node *y = e->callee->
+				function_or_virtual_thunk_symbol (&avail);
 
 	      if (avail > AVAIL_INTERPOSABLE)
 		can_free = get_function_state (y)->can_free;
@@ -1517,7 +1521,8 @@ propagate_nothrow (void)
 	  for (e = w->callees; e && !can_throw; e = e->next_callee)
 	    {
 	      enum availability avail;
-	      struct cgraph_node *y = e->callee->function_symbol (&avail);
+	      struct cgraph_node *y = e->callee->
+				function_or_virtual_thunk_symbol (&avail);
 
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
Index: gcc/testsuite/g++.old-deja/g++.mike/p4736b.C
===================================================================
--- gcc/testsuite/g++.old-deja/g++.mike/p4736b.C	(revision 218024)
+++ gcc/testsuite/g++.old-deja/g++.mike/p4736b.C	(working copy)
@@ -1,4 +1,5 @@
 // { dg-do run  }
+// { dg-options "-O2" }
 // prms-id: 4736
 
 class Rep {
