Tested on Linux/X86-32. 2011-05-13 Ville Voutilainen <ville.voutilai...@gmail.com> <ville.voutilai...@symbio.com> Implement final on class. * class.c (check_bases): Diagnose derivation from a final class. * cp-tree.h (lang_type_class): Add is_final and adjust dummy. * cp-tree.h (CLASSTYPE_FINAL): New. * parser.c (cp_parser_class_head): Parse class-virt-specifier, set CLASSTYPE_FINAL. * pt.c (instantiate_class_template_1): Copy the CLASSTYPE_FINAL.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 293dd1c..44b1d8e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1268,6 +1268,10 @@ check_bases (tree t, gcc_assert (COMPLETE_TYPE_P (basetype)); + if (CLASSTYPE_FINAL (basetype)) + error ("cannot derive from from final base %qT in derived type %qT", + basetype, t); + /* If any base class is non-literal, so is the derived class. */ if (!CLASSTYPE_LITERAL_P (basetype)) CLASSTYPE_LITERAL_P (t) = false; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1705232..901a17d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1321,6 +1321,7 @@ struct GTY(()) lang_type_class { unsigned has_complex_move_ctor : 1; unsigned has_complex_move_assign : 1; unsigned has_constexpr_ctor : 1; + unsigned is_final : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -1329,7 +1330,7 @@ struct GTY(()) lang_type_class { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 3; + unsigned dummy : 2; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -1437,6 +1438,11 @@ struct GTY((variable_size)) lang_type { #define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->lazy_destructor) +/* Nonzero means that NODE (a class type) is final */ +#define CLASSTYPE_FINAL(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->is_final) + + /* Nonzero means that this _CLASSTYPE node overloads operator=(X&). */ #define TYPE_HAS_COPY_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_copy_assign) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index fa6cd83..5e9b8a8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -17117,6 +17117,7 @@ cp_parser_class_head (cp_parser* parser, tree id = NULL_TREE; tree type = NULL_TREE; tree attributes; + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; bool template_id_p = false; bool qualified_p = false; bool invalid_nested_name_p = false; @@ -17260,8 +17261,11 @@ cp_parser_class_head (cp_parser* parser, pop_deferring_access_checks (); if (id) - cp_parser_check_for_invalid_template_id (parser, id, - type_start_token->location); + { + virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); + cp_parser_check_for_invalid_template_id (parser, id, + type_start_token->location); + } /* If it's not a `:' or a `{' then we can't really be looking at a class-head, since a class-head only appears as part of a @@ -17493,6 +17497,8 @@ cp_parser_class_head (cp_parser* parser, if (type) DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location; *attributes_p = attributes; + if (virt_specifiers & VIRT_SPEC_FINAL) + CLASSTYPE_FINAL (type) = 1; out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; return type; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5e24977..5e059e0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8209,6 +8209,7 @@ instantiate_class_template_1 (tree type) CLASSTYPE_VISIBILITY_SPECIFIED (type) = 1; CLASSTYPE_VISIBILITY (type) = CLASSTYPE_VISIBILITY (pattern); } + CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern); pbinfo = TYPE_BINFO (pattern); diff --git a/gcc/testsuite/g++.dg/inherit/base4.C b/gcc/testsuite/g++.dg/inherit/base4.C new file mode 100644 index 0000000..5736193 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/base4.C @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options "--std=c++0x" } +struct B1 {}; + +struct B2 final {}; + +struct D1 : B1 {}; + +struct D2 : B2 {}; // { dg-error "cannot derive from from final base" } + +template<class T> struct D3 : T {}; + +template<class T> struct D4 : T {}; // { dg-error "cannot derive from from final base" } + +struct B3 final final {}; // { dg-error "duplicate virt-specifier" } + +int main() +{ + D3<B1> d; + D4<B2> d2; + struct B2 final{}; + struct B1 final2{}; +}