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.

From-SVN: r173761
This commit is contained in:
Ville Voutilainen 2011-05-14 21:13:23 +03:00 committed by Jason Merrill
parent ade2e40389
commit 486d481b39
8 changed files with 93 additions and 4 deletions

View File

@ -1,3 +1,13 @@
2011-05-13 Ville Voutilainen <ville.voutilainen@gmail.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.
(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 <jason@redhat.com> 2011-05-13 Jason Merrill <jason@redhat.com>
PR c++/48969 PR c++/48969

View File

@ -1268,6 +1268,10 @@ check_bases (tree t,
gcc_assert (COMPLETE_TYPE_P (basetype)); gcc_assert (COMPLETE_TYPE_P (basetype));
if (CLASSTYPE_FINAL (basetype))
error ("cannot derive from %<final%> base %qT in derived type %qT",
basetype, t);
/* If any base class is non-literal, so is the derived class. */ /* If any base class is non-literal, so is the derived class. */
if (!CLASSTYPE_LITERAL_P (basetype)) if (!CLASSTYPE_LITERAL_P (basetype))
CLASSTYPE_LITERAL_P (t) = false; CLASSTYPE_LITERAL_P (t) = false;

View File

@ -1322,6 +1322,7 @@ struct GTY(()) lang_type_class {
unsigned has_complex_move_ctor : 1; unsigned has_complex_move_ctor : 1;
unsigned has_complex_move_assign : 1; unsigned has_complex_move_assign : 1;
unsigned has_constexpr_ctor : 1; unsigned has_constexpr_ctor : 1;
unsigned is_final : 1;
/* When adding a flag here, consider whether or not it ought to /* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If 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 /* 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 of this by updating the size of this bitfield whenever you add or
remove a flag. */ remove a flag. */
unsigned dummy : 3; unsigned dummy : 2;
tree primary_base; tree primary_base;
VEC(tree_pair_s,gc) *vcall_indices; VEC(tree_pair_s,gc) *vcall_indices;
@ -1438,6 +1439,11 @@ struct GTY((variable_size)) lang_type {
#define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \ #define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_destructor) (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&). */ /* Nonzero means that this _CLASSTYPE node overloads operator=(X&). */
#define TYPE_HAS_COPY_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_copy_assign) #define TYPE_HAS_COPY_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_copy_assign)

View File

@ -17082,10 +17082,13 @@ cp_parser_class_specifier (cp_parser* parser)
class-head: class-head:
class-key identifier [opt] base-clause [opt] 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 class-key nested-name-specifier [opt] template-id
base-clause [opt] base-clause [opt]
class-virt-specifier:
final
GNU Extensions: GNU Extensions:
class-key attributes identifier [opt] base-clause [opt] class-key attributes identifier [opt] base-clause [opt]
class-key attributes nested-name-specifier identifier 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 id = NULL_TREE;
tree type = NULL_TREE; tree type = NULL_TREE;
tree attributes; tree attributes;
cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
bool template_id_p = false; bool template_id_p = false;
bool qualified_p = false; bool qualified_p = false;
bool invalid_nested_name_p = false; bool invalid_nested_name_p = false;
@ -17260,8 +17264,11 @@ cp_parser_class_head (cp_parser* parser,
pop_deferring_access_checks (); pop_deferring_access_checks ();
if (id) 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 /* 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 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 /* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */ if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser); cp_parser_commit_to_tentative_parse (parser);
if (virt_specifiers & VIRT_SPEC_OVERRIDE)
{
cp_parser_error (parser,
"cannot specify %<override%> for a class");
type = error_mark_node;
goto out;
}
/* Issue the error about the overly-qualified name now. */ /* Issue the error about the overly-qualified name now. */
if (qualified_p) if (qualified_p)
{ {
@ -17493,6 +17507,8 @@ cp_parser_class_head (cp_parser* parser,
if (type) if (type)
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location; DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
*attributes_p = attributes; *attributes_p = attributes;
if (type && (virt_specifiers & VIRT_SPEC_FINAL))
CLASSTYPE_FINAL (type) = 1;
out: out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type; return type;

View File

@ -8209,6 +8209,7 @@ instantiate_class_template_1 (tree type)
CLASSTYPE_VISIBILITY_SPECIFIED (type) = 1; CLASSTYPE_VISIBILITY_SPECIFIED (type) = 1;
CLASSTYPE_VISIBILITY (type) = CLASSTYPE_VISIBILITY (pattern); CLASSTYPE_VISIBILITY (type) = CLASSTYPE_VISIBILITY (pattern);
} }
CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
pbinfo = TYPE_BINFO (pattern); pbinfo = TYPE_BINFO (pattern);

View File

@ -1,3 +1,8 @@
2011-05-13 Ville Voutilainen <ville.voutilainen@gmail.com>
* g++.dg/cpp0x/override1.C: Move from inherit/virtual9.C.
* g++.dg/cpp0x/override2.C: New.
2011-05-14 Tobias Burnus <burnus@net-b.de> 2011-05-14 Tobias Burnus <burnus@net-b.de>
PR fortran/18918 PR fortran/18918

View File

@ -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<class T> struct D3 : T {};
template<class T> struct D4 : T {}; // { dg-error "cannot derive from 'final' base" }
template <class T> struct B3 {};
template <class T> struct B4 final {};
template <class T> struct B5 final {};
struct undeclared<int> final { }; // { dg-error "not a template" }
struct D5 : B3<D5> {};
struct D6 : B4<D6> {}; // { 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<B1> d;
D4<B2> 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" }
}