Index: cgraph.c
===================================================================
--- cgraph.c	(revision 201814)
+++ cgraph.c	(working copy)
@@ -925,6 +925,7 @@ cgraph_create_indirect_edge (struct cgra
 {
   struct cgraph_edge *edge = cgraph_create_edge_1 (caller, NULL, call_stmt,
 						   count, freq);
+  tree target;
 
   edge->indirect_unknown_callee = 1;
   initialize_inline_failed (edge);
@@ -932,6 +933,23 @@ cgraph_create_indirect_edge (struct cgra
   edge->indirect_info = cgraph_allocate_init_indirect_info ();
   edge->indirect_info->ecf_flags = ecf_flags;
 
+  /* Record polymorphic call info.  */
+  if (call_stmt
+      && (target = gimple_call_fn (call_stmt))
+      && virtual_method_call_p (target))
+    {
+      tree type = obj_type_ref_class (target);
+
+
+      /* Only record types can have virtual calls.  */
+      gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+      edge->indirect_info->param_index = -1;
+      edge->indirect_info->otr_token
+	 = tree_low_cst (OBJ_TYPE_REF_TOKEN (target), 1);
+      edge->indirect_info->otr_type = type;
+      edge->indirect_info->polymorphic = 1;
+    }
+
   edge->next_callee = caller->indirect_calls;
   if (caller->indirect_calls)
     caller->indirect_calls->prev_callee = edge;
Index: gimple-fold.c
===================================================================
--- gimple-fold.c	(revision 201814)
+++ gimple-fold.c	(working copy)
@@ -1105,7 +1105,7 @@ gimple_fold_call (gimple_stmt_iterator *
 	  gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee));
 	  changed = true;
 	}
-      else
+      else if (virtual_method_call_p (callee))
 	{
 	  tree obj = OBJ_TYPE_REF_OBJECT (callee);
 	  tree binfo = gimple_extract_devirt_binfo_from_cst
Index: ipa-cp.c
===================================================================
--- ipa-cp.c	(revision 201814)
+++ ipa-cp.c	(working copy)
@@ -734,7 +734,8 @@ initialize_node_lattices (struct cgraph_
     }
 
   for (ie = node->indirect_calls; ie; ie = ie->next_callee)
-    if (ie->indirect_info->polymorphic)
+    if (ie->indirect_info->polymorphic
+        && ie->indirect_info->param_index >= 0)
       {
 	gcc_checking_assert (ie->indirect_info->param_index >= 0);
 	ipa_get_parm_lattices (info,
Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 201814)
+++ ipa-prop.c	(working copy)
@@ -1922,7 +1922,7 @@ ipa_analyze_call_uses (struct cgraph_nod
     return;
   if (TREE_CODE (target) == SSA_NAME)
     ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
-  else if (TREE_CODE (target) == OBJ_TYPE_REF)
+  else if (virtual_method_call_p (target))
     ipa_analyze_virtual_call_uses (node, info, call, target);
 }
 
Index: tree.c
===================================================================
--- tree.c	(revision 201817)
+++ tree.c	(working copy)
@@ -11864,6 +11864,27 @@ types_same_for_odr (tree type1, tree typ
   return true;
 }
 
+/* TARGET is a call target of GIMPLE call statement
+   (obtained by gimple_call_fn).  Return true if it is
+   OBJ_TYPE_REF representing an virtual call of C++ method.
+   (As opposed to OBJ_TYPE_REF representing objc calls
+   through a cast where middle-end devirtualization machinery
+   can't apply.) */
+
+bool
+virtual_method_call_p (tree target)
+{
+  if (TREE_CODE (target) != OBJ_TYPE_REF)
+    return false;
+  target = TREE_TYPE (target);
+  gcc_checking_assert (TREE_CODE (target) == POINTER_TYPE);
+  target = TREE_TYPE (target);
+  if (TREE_CODE (target) == FUNCTION_TYPE)
+    return false;
+  gcc_checking_assert (TREE_CODE (target) == METHOD_TYPE);
+  return true;
+}
+
 /* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
 
 tree
Index: tree.h
===================================================================
--- tree.h	(revision 201814)
+++ tree.h	(working copy)
@@ -5974,6 +5974,7 @@ extern location_t tree_nonartificial_loc
 extern tree block_ultimate_origin (const_tree);
 
 extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
+extern bool virtual_method_call_p (tree);
 extern tree obj_type_ref_class (tree ref);
 extern bool types_same_for_odr (tree type1, tree type2);
 extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
