diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f13180fb973..cb3246148fa 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2725,6 +2725,7 @@ override_one_vtable (binfo, old, t) fndecl = copy_node (fndecl); copy_lang_decl (fndecl); DECL_ABSTRACT_VIRTUAL_P (fndecl) = 1; + DECL_NEEDS_FINAL_OVERRIDER_P (fndecl) = 1; /* Make sure we search for it later. */ if (! CLASSTYPE_ABSTRACT_VIRTUALS (t)) CLASSTYPE_ABSTRACT_VIRTUALS (t) = error_mark_node; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index fdf704c3ec9..43a1660a988 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2740,6 +2740,7 @@ duplicate_decls (newdecl, olddecl) DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl); DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl); DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); + DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); } /* Deal with C++: must preserve virtual function table size. */ diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f462e79bc84..2a208afd149 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -130,6 +130,29 @@ abstract_virtuals_error (decl, type) tree type; { tree u = CLASSTYPE_ABSTRACT_VIRTUALS (type); + int has_abstract_virtuals, needs_final_overriders; + tree tu; + + /* Count how many abstract methods need to be defined. */ + for (has_abstract_virtuals = 0, tu = u; tu; tu = TREE_CHAIN (tu)) + { + if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu)) + && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu))) + { + has_abstract_virtuals = 1; + break; + } + } + + /* Count how many virtual methods need a final overrider. */ + for (needs_final_overriders = 0, tu = u; tu; tu = TREE_CHAIN (tu)) + { + if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu))) + { + needs_final_overriders = 1; + break; + } + } if (decl) { @@ -151,19 +174,52 @@ abstract_virtuals_error (decl, type) else if (TREE_CODE (decl) == FUNCTION_DECL) cp_error ("invalid return type for function `%#D'", decl); } - else cp_error ("cannot allocate an object of type `%T'", type); + else + cp_error ("cannot allocate an object of type `%T'", type); + /* Only go through this once. */ if (TREE_PURPOSE (u) == NULL_TREE) { - error (" since the following virtual functions are abstract:"); TREE_PURPOSE (u) = error_mark_node; - while (u) + + if (has_abstract_virtuals) + error (" since the following virtual functions are abstract:"); + tu = u; + while (tu) { - cp_error ("\t%#D", TREE_VALUE (u)); - u = TREE_CHAIN (u); + if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu)) + && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu))) + cp_error ("\t%#D", TREE_VALUE (tu)); + tu = TREE_CHAIN (tu); + } + + if (needs_final_overriders) + { + if (has_abstract_virtuals) + error (" and the following virtual functions need a final overrider:"); + else + error (" since the following virtual functions need a final overrider:"); + } + tu = u; + while (tu) + { + if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu))) + cp_error ("\t%#D", TREE_VALUE (tu)); + tu = TREE_CHAIN (tu); } } - else cp_error (" since type `%T' has abstract virtual functions", type); + else + { + if (has_abstract_virtuals) + { + if (needs_final_overriders) + cp_error (" since type `%T' has abstract virtual functions and must override virtual functions", type); + else + cp_error (" since type `%T' has abstract virtual functions", type); + } + else + cp_error (" since type `%T' must override virtual functions", type); + } } /* Print an error message for invalid use of a signature type.