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:
parent
ade2e40389
commit
486d481b39
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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,
|
cp_parser_check_for_invalid_template_id (parser, id,
|
||||||
type_start_token->location);
|
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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
47
gcc/testsuite/g++.dg/cpp0x/override2.C
Normal file
47
gcc/testsuite/g++.dg/cpp0x/override2.C
Normal 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" }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user