Hi, this patch adds ipa-devirt code for final types and methods. There is probably no way to construct a testcase that will be devirtualized, since all the simple minded devirtualization is already done by FE. I however checked that dumps seems sane at least. Once we are able to track types of THIS pointers, this will become interesting.
Bootstrapped/regtested x86_64-linux, will commit it shortly. Honza * ipa-devirt.c (struct odr_type_d): Add final_type field. (dump_odr_type): Add dumping. (possible_polymorphic_call_targets): Support final types and final methods. Index: ipa-devirt.c =================================================================== --- ipa-devirt.c (revision 201974) +++ ipa-devirt.c (working copy) @@ -137,6 +137,8 @@ struct GTY(()) odr_type_d int id; /* Is it in anonymous namespace? */ bool anonymous_namespace; + /* Is it final type? */ + bool final_type; }; @@ -270,6 +272,7 @@ get_odr_type (tree type, bool insert) val->bases = vNULL; val->derived_types = vNULL; val->anonymous_namespace = type_in_anonymous_namespace_p (type); + val->final_type = TYPE_FINAL_P (type); *slot = val; for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++) /* For now record only polymorphic types. other are @@ -300,7 +303,8 @@ dump_odr_type (FILE *f, odr_type t, int unsigned int i; fprintf (f, "%*s type %i: ", indent * 2, "", t->id); print_generic_expr (f, t->type, TDF_SLIM); - fprintf (f, "%s\n", t->anonymous_namespace ? " (anonymous namespace)":""); + fprintf (f, "%s%s\n", t->anonymous_namespace ? " (anonymous namespace)":"", + t->final_type ? " (final)":""); if (TYPE_NAME (t->type)) { fprintf (f, "%*s defined at: %s:%i\n", indent * 2, "", @@ -598,7 +602,7 @@ possible_polymorphic_call_targets (tree /* For anonymous namespace types we can attempt to build full type. All derivations must be in this unit. */ - if (type->anonymous_namespace && finalp && !flag_ltrans) + if ((type->anonymous_namespace || type->final_type) && finalp && !flag_ltrans) *finalp = true; /* Initialize query cache. */ @@ -637,19 +641,24 @@ possible_polymorphic_call_targets (tree target = gimple_get_virt_method_for_binfo (otr_token, binfo); if (target) maybe_record_node (nodes, target, inserted); - pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo)); - /* TODO: If method is final, we can stop here and signaize that - list is final. We need C++ FE to pass our info about final - methods and classes. */ + /* If we failed to find the method, we no longer have final list + This can happen i.e. when we can not refer to decl from other unit. */ + if (!nodes.length()) + *finalp = false; + pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo)); - /* Walk recursively all derived types. Here we need to lookup proper basetype - via their BINFO walk that is done by record_binfo */ - for (i = 0; i < type->derived_types.length(); i++) - possible_polymorphic_call_targets_1 (nodes, inserted, - matched_vtables, - otr_type, type->derived_types[i], - otr_token); + /* If method is not final, walk recursively all derived types. + Here we need to lookup proper basetype via their BINFO walk that is done + by record_binfo */ + if (!nodes.length () || !DECL_FINAL_P (nodes[0]->symbol.decl)) + for (i = 0; i < type->derived_types.length(); i++) + possible_polymorphic_call_targets_1 (nodes, inserted, + matched_vtables, + otr_type, type->derived_types[i], + otr_token); + else if (finalp) + *finalp = true; (*slot)->targets = nodes; pointer_set_destroy (inserted);