From b5da71d41644c40db95aabac8f67c28294f4c85f Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 9 May 2011 20:34:35 +0300 Subject: [PATCH] Implement final/override for member functions. gcc/ * tree.h (TYPE_UNQUALIFIED, TYPE_QUAL_CONST): Convert to enum. (TYPE_QUAL_VOLATILE, TYPE_QUAL_RESTRICT): Likewise. gcc/cp/ * class.c (check_for_override): Check for DECL_OVERRIDE_P. * cp-tree.h (DECL_OVERRIDE_P, DECL_FINAL_P): New. (cp_virt_specifiers, enum virt_specifier): New. * decl.c (set_virt_specifiers): New. (grokdeclarator): Use them. Diagnose virt-specifiers on non-fields. * parser.c (make_call_declarator): add virt-specifiers parameter. (cp_parser_lambda_declarator_opt): Adjust. (cp_parser_direct_declarator): Likewise. (cp_parser_virt_specifier_seq_opt): New. * search.c (check_final_overrider): Diagnose attempts to override a final member function. From-SVN: r173581 --- gcc/ChangeLog | 5 +++ gcc/cp/ChangeLog | 15 +++++++ gcc/cp/class.c | 5 +++ gcc/cp/cp-tree.h | 28 ++++++++++++ gcc/cp/decl.c | 28 +++++++++++- gcc/cp/parser.c | 58 ++++++++++++++++++++++++- gcc/cp/search.c | 6 +++ gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/inherit/virtual9.C | 39 +++++++++++++++++ gcc/tree.h | 12 ++--- 10 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/inherit/virtual9.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 18790b80511..6406136d7e9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2011-05-08 Ville Voutilainen + + * tree.h (TYPE_UNQUALIFIED, TYPE_QUAL_CONST): Convert to enum. + (TYPE_QUAL_VOLATILE, TYPE_QUAL_RESTRICT): Likewise. + 2011-05-09 Uros Bizjak * config/i386/predicates.md (const_pow2_1_to_2_operand): Remove. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9bd20b16b84..17116e00b61 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2011-05-08 Ville Voutilainen + + Implement final/override for member functions. + * class.c (check_for_override): Check for DECL_OVERRIDE_P. + * cp-tree.h (DECL_OVERRIDE_P, DECL_FINAL_P): New. + (cp_virt_specifiers, enum virt_specifier): New. + * decl.c (set_virt_specifiers): New. + (grokdeclarator): Use them. Diagnose virt-specifiers on non-fields. + * parser.c (make_call_declarator): add virt-specifiers parameter. + (cp_parser_lambda_declarator_opt): Adjust. + (cp_parser_direct_declarator): Likewise. + (cp_parser_virt_specifier_seq_opt): New. + * search.c (check_final_overrider): Diagnose attempts to override + a final member function. + 2011-05-09 Dodji Seketeli PR c++/48574 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6b08a038e0b..12db2bcb093 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2477,6 +2477,11 @@ check_for_override (tree decl, tree ctype) if (DECL_DESTRUCTOR_P (decl)) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true; } + else if (DECL_OVERRIDE_P (decl)) + { + DECL_VINDEX (decl) = error_mark_node; + error ("%q+#D marked override, but does not override", decl); + } } /* Warn about hidden virtual functions that are not overridden in t. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ad298dfd575..a03d6a11bca 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -72,6 +72,7 @@ c-common.h, not after. LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR) DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE) VEC_INIT_EXPR_IS_CONSTEXPR (in VEC_INIT_EXPR) + DECL_OVERRIDE_P (in FUNCTION_DECL) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -84,6 +85,7 @@ c-common.h, not after. TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR) LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR) DECLTYPE_FOR_LAMBDA_RETURN (in DECLTYPE_TYPE) + DECL_FINAL_P (in FUNCTION_DECL) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -2284,6 +2286,14 @@ struct GTY((variable_size)) lang_decl { #define DECL_INVALID_OVERRIDER_P(NODE) \ (DECL_LANG_FLAG_4 (NODE)) +/* True (in a FUNCTION_DECL) if NODE is a function declared with + an override virt-specifier */ +#define DECL_OVERRIDE_P(NODE) (TREE_LANG_FLAG_0 (NODE)) + +/* True (in a FUNCTION_DECL) if NODE is a function declared with + a final virt-specifier */ +#define DECL_FINAL_P(NODE) (TREE_LANG_FLAG_1 (NODE)) + /* The thunks associated with NODE, a FUNCTION_DECL. */ #define DECL_THUNKS(NODE) \ (LANG_DECL_FN_CHECK (NODE)->context) @@ -4429,6 +4439,22 @@ extern GTY(()) operator_name_info_t assignment_operator_name_info typedef int cp_cv_quals; +/* Non-static member functions have an optional virt-specifier-seq. + There is a VIRT_SPEC value for each virt-specifier. + They can be combined by bitwise-or to form the complete set of + virt-specifiers for a member function. */ +enum virt_specifier + { + VIRT_SPEC_UNSPECIFIED = 0x0, + VIRT_SPEC_FINAL = 0x1, + VIRT_SPEC_OVERRIDE = 0x2 + }; + +/* A type-qualifier, or bitmask therefore, using the VIRT_SPEC + constants. */ + +typedef int cp_virt_specifiers; + /* A storage class. */ typedef enum cp_storage_class { @@ -4571,6 +4597,8 @@ struct cp_declarator { tree parameters; /* The cv-qualifiers for the function. */ cp_cv_quals qualifiers; + /* The virt-specifiers for the function. */ + cp_virt_specifiers virt_specifiers; /* The exception-specification for the function. */ tree exception_specification; /* The late-specified return type, if any. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 764d5dffb17..c139f3f0ba4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7306,6 +7306,25 @@ grokfndecl (tree ctype, return decl; } +/* decl is a FUNCTION_DECL. + specifiers are the parsed virt-specifiers. + + Set flags to reflect the virt-specifiers. + + Returns decl. */ + +static tree +set_virt_specifiers (tree decl, cp_virt_specifiers specifiers) +{ + if (decl == NULL_TREE) + return decl; + if (specifiers & VIRT_SPEC_OVERRIDE) + DECL_OVERRIDE_P (decl) = 1; + if (specifiers & VIRT_SPEC_FINAL) + DECL_FINAL_P (decl) = 1; + return decl; +} + /* DECL is a VAR_DECL for a static data member. Set flags to reflect the linkage that DECL will receive in the object file. */ @@ -8116,6 +8135,9 @@ grokdeclarator (const cp_declarator *declarator, /* cv-qualifiers that apply to the declarator, for a declaration of a member function. */ cp_cv_quals memfn_quals = TYPE_UNQUALIFIED; + /* virt-specifiers that apply to the declarator, for a declaration of + a member function. */ + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; /* cv-qualifiers that apply to the type specified by the DECLSPECS. */ int type_quals; tree raises = NULL_TREE; @@ -8876,7 +8898,8 @@ grokdeclarator (const cp_declarator *declarator, /* Pick up type qualifiers which should be applied to `this'. */ memfn_quals = declarator->u.function.qualifiers; - + /* Pick up virt-specifiers. */ + virt_specifiers = declarator->u.function.virt_specifiers; /* Pick up the exception specifications. */ raises = declarator->u.function.exception_specification; @@ -9814,6 +9837,7 @@ grokdeclarator (const cp_declarator *declarator, sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); + decl = set_virt_specifiers (decl, virt_specifiers); if (decl == NULL_TREE) return error_mark_node; #if 0 @@ -10007,6 +10031,8 @@ grokdeclarator (const cp_declarator *declarator, else if (thread_p) error ("storage class %<__thread%> invalid for function %qs", name); + if (virt_specifiers) + error ("virt-specifiers in %qs not allowed outside a class definition", name); /* Function declaration not at top level. Storage classes other than `extern' are not allowed and `extern' makes no difference. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 82495b65c0a..fa6cd83ed30 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -938,7 +938,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs) VAR_DECLs or FUNCTION_DECLs) should do that directly. */ static cp_declarator *make_call_declarator - (cp_declarator *, tree, cp_cv_quals, tree, tree); + (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, tree, tree); static cp_declarator *make_array_declarator (cp_declarator *, tree); static cp_declarator *make_pointer_declarator @@ -1103,6 +1103,7 @@ cp_declarator * make_call_declarator (cp_declarator *target, tree parms, cp_cv_quals cv_qualifiers, + cp_virt_specifiers virt_specifiers, tree exception_specification, tree late_return_type) { @@ -1112,6 +1113,7 @@ make_call_declarator (cp_declarator *target, declarator->declarator = target; declarator->u.function.parameters = parms; declarator->u.function.qualifiers = cv_qualifiers; + declarator->u.function.virt_specifiers = virt_specifiers; declarator->u.function.exception_specification = exception_specification; declarator->u.function.late_return_type = late_return_type; if (target) @@ -1691,6 +1693,8 @@ static enum tree_code cp_parser_ptr_operator (cp_parser *, tree *, cp_cv_quals *); static cp_cv_quals cp_parser_cv_qualifier_seq_opt (cp_parser *); +static cp_virt_specifiers cp_parser_virt_specifier_seq_opt + (cp_parser *); static tree cp_parser_late_return_type_opt (cp_parser *); static tree cp_parser_declarator_id @@ -7665,6 +7669,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr) ? TYPE_UNQUALIFIED : TYPE_QUAL_CONST); declarator = make_call_declarator (declarator, param_list, quals, + VIRT_SPEC_UNSPECIFIED, exception_spec, /*late_return_type=*/NULL_TREE); declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr); @@ -14894,6 +14899,7 @@ cp_parser_direct_declarator (cp_parser* parser, if (member_p || cp_parser_parse_definitely (parser)) { cp_cv_quals cv_quals; + cp_virt_specifiers virt_specifiers; tree exception_specification; tree late_return; @@ -14910,6 +14916,8 @@ cp_parser_direct_declarator (cp_parser* parser, /* And the exception-specification. */ exception_specification = cp_parser_exception_specification_opt (parser); + /* Parse the virt-specifier-seq. */ + virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); late_return = cp_parser_late_return_type_opt (parser); @@ -14918,6 +14926,7 @@ cp_parser_direct_declarator (cp_parser* parser, declarator = make_call_declarator (declarator, params, cv_quals, + virt_specifiers, exception_specification, late_return); /* Any subsequent parameter lists are to do with @@ -15425,6 +15434,53 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser) return cv_quals; } +/* Parse an (optional) virt-specifier-seq. + + virt-specifier-seq: + virt-specifier virt-specifier-seq [opt] + + virt-specifier: + override + final + + Returns a bitmask representing the virt-specifiers. */ + +static cp_virt_specifiers +cp_parser_virt_specifier_seq_opt (cp_parser* parser) +{ + cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED; + + while (true) + { + cp_token *token; + cp_virt_specifiers virt_specifier; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* See if it's a virt-specifier-qualifier. */ + if (token->type != CPP_NAME) + break; + if (!strcmp (IDENTIFIER_POINTER(token->u.value), "override")) + virt_specifier = VIRT_SPEC_OVERRIDE; + else if (!strcmp (IDENTIFIER_POINTER(token->u.value), "final")) + virt_specifier = VIRT_SPEC_FINAL; + else + break; + + if (virt_specifiers & virt_specifier) + { + error_at (token->location, "duplicate virt-specifier"); + cp_lexer_purge_token (parser->lexer); + } + else + { + cp_lexer_consume_token (parser->lexer); + virt_specifiers |= virt_specifier; + } + } + return virt_specifiers; +} + /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like diff --git a/gcc/cp/search.c b/gcc/cp/search.c index e7d2048e89f..cf0b1a0a7e0 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1920,6 +1920,12 @@ check_final_overrider (tree overrider, tree basefn) } return 0; } + if (DECL_FINAL_P (basefn)) + { + error ("virtual function %q+D", overrider); + error ("overriding final function %q+D", basefn); + return 0; + } return 1; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b15dba9b350..5b72fc5d6c6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-05-08 Ville Voutilainen + + * g++.dg/inherit/virtual9.C: New. + 2011-05-09 Dodji Seketeli PR c++/48574 diff --git a/gcc/testsuite/g++.dg/inherit/virtual9.C b/gcc/testsuite/g++.dg/inherit/virtual9.C new file mode 100644 index 00000000000..d3175e14798 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/virtual9.C @@ -0,0 +1,39 @@ +// { dg-do compile } +struct B +{ + virtual void f() final {} + virtual void g() {} +}; + +struct B2 +{ + virtual void h() {} +}; + +struct D : B +{ + virtual void g() override final {} // { dg-error "overriding" } +}; + +template struct D2 : T +{ + void h() override {} // { dg-error "marked override, but does not override" } +}; + +struct D3 : D +{ + void g() {} // { dg-error "virtual function" } +}; + +struct B3 +{ + virtual void f() final final {} // { dg-error "duplicate virt-specifier" } +}; + +void g() override {} // { dg-error "virt-specifiers" } + +int main() +{ + D2 d2; + D2 d3; +} diff --git a/gcc/tree.h b/gcc/tree.h index d0cd3e05b25..4cf1730d4cb 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2253,11 +2253,13 @@ extern enum machine_mode vector_type_mode (const_tree); /* There is a TYPE_QUAL value for each type qualifier. They can be combined by bitwise-or to form the complete set of qualifiers for a type. */ - -#define TYPE_UNQUALIFIED 0x0 -#define TYPE_QUAL_CONST 0x1 -#define TYPE_QUAL_VOLATILE 0x2 -#define TYPE_QUAL_RESTRICT 0x4 +enum cv_qualifier + { + TYPE_UNQUALIFIED = 0x0, + TYPE_QUAL_CONST = 0x1, + TYPE_QUAL_VOLATILE = 0x2, + TYPE_QUAL_RESTRICT = 0x4 + }; /* Encode/decode the named memory support as part of the qualifier. If more than 8 qualifiers are added, these macros need to be adjusted. */ -- 2.30.2