diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a42e3e3ac8..f0371ad8b01 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2011-05-13 Ville Voutilainen + + 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. + (CLASSTYPE_FINAL): New. + * parser.c (cp_parser_class_head): Parse class-virt-specifier, set + CLASSTYPE_FINAL. + * pt.c (instantiate_class_template_1): Copy CLASSTYPE_FINAL. + 2011-05-13 Jason Merrill PR c++/48969 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 938d52201e3..dc2c509a8cf 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 % 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 bcf78f8f14e..c0b52908883 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1322,6 +1322,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 @@ -1330,7 +1331,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; @@ -1438,6 +1439,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 fa6cd83ed30..a77d4ffb6ac 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -17082,10 +17082,13 @@ cp_parser_class_specifier (cp_parser* parser) class-head: class-key identifier [opt] base-clause [opt] - class-key nested-name-specifier identifier base-clause [opt] + class-key nested-name-specifier identifier class-virt-specifier [opt] base-clause [opt] class-key nested-name-specifier [opt] template-id base-clause [opt] + class-virt-specifier: + final + GNU Extensions: class-key attributes identifier [opt] base-clause [opt] class-key attributes nested-name-specifier identifier base-clause [opt] @@ -17117,6 +17120,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 +17264,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); + { + cp_parser_check_for_invalid_template_id (parser, id, + type_start_token->location); + virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); + } /* 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 @@ -17277,6 +17284,13 @@ cp_parser_class_head (cp_parser* parser, /* At this point, we're going ahead with the class-specifier, even if some other problem occurs. */ cp_parser_commit_to_tentative_parse (parser); + if (virt_specifiers & VIRT_SPEC_OVERRIDE) + { + cp_parser_error (parser, + "cannot specify % for a class"); + type = error_mark_node; + goto out; + } /* Issue the error about the overly-qualified name now. */ if (qualified_p) { @@ -17493,6 +17507,8 @@ cp_parser_class_head (cp_parser* parser, if (type) DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location; *attributes_p = attributes; + if (type && (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 f155c1ab61d..e441a706d65 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/ChangeLog b/gcc/testsuite/ChangeLog index f014a807532..b7a8f50d593 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-05-13 Ville Voutilainen + + * g++.dg/cpp0x/override1.C: Move from inherit/virtual9.C. + * g++.dg/cpp0x/override2.C: New. + 2011-05-14 Tobias Burnus PR fortran/18918 diff --git a/gcc/testsuite/g++.dg/inherit/virtual9.C b/gcc/testsuite/g++.dg/cpp0x/override1.C similarity index 100% rename from gcc/testsuite/g++.dg/inherit/virtual9.C rename to gcc/testsuite/g++.dg/cpp0x/override1.C diff --git a/gcc/testsuite/g++.dg/cpp0x/override2.C b/gcc/testsuite/g++.dg/cpp0x/override2.C new file mode 100644 index 00000000000..7f17504fae2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/override2.C @@ -0,0 +1,47 @@ +// { dg-do compile } +// { dg-options "--std=c++0x" } +struct B1 {}; + +struct B2 final {}; + +struct D1 : B1 {}; + +struct D2 : B2 {}; // { dg-error "cannot derive from 'final' base" } + +template struct D3 : T {}; + +template struct D4 : T {}; // { dg-error "cannot derive from 'final' base" } + +template struct B3 {}; + +template struct B4 final {}; + +template struct B5 final {}; + +struct undeclared final { }; // { dg-error "not a template" } + +struct D5 : B3 {}; + +struct D6 : B4 {}; // { dg-error "cannot derive from 'final' base" } + +struct B6 final final {}; // { dg-error "duplicate virt-specifier" } + +struct B7 override {}; // { dg-error "cannot specify 'override' for a class" } + +int main() +{ + D3 d; + D4 d2; + struct B2 final{}; // { dg-error "previous definition" } + B2 final; // { dg-error "has a previous declaration|previously declared here" } + B2 final2 = final; + struct B2 {}; // { dg-error "redefinition" } + struct B2 final; // { dg-error "redeclaration" } + struct B2 override; // { dg-error "previously declared here" } + struct B2 final {}; // { dg-error "redefinition" } + struct B2 override {}; // { dg-error "cannot specify 'override' for a class" } + B2 override{}; // { dg-error "redeclaration" } + struct foo final {}; // { dg-error "previous definition" } + struct foo final {}; // { dg-error "redefinition" } + foo final; // { dg-error "conflicting declaration" } +}