Implement final/override for member functions.
authorVille Voutilainen <ville.voutilainen@gmail.com>
Mon, 9 May 2011 17:34:35 +0000 (20:34 +0300)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 9 May 2011 17:34:35 +0000 (13:34 -0400)
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
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/search.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/inherit/virtual9.C [new file with mode: 0644]
gcc/tree.h

index 18790b8051126138c5c668df1488c5a576c8c6d9..6406136d7e99b3a4c3b6df19d5f1fd885c4f77e4 100644 (file)
@@ -1,3 +1,8 @@
+2011-05-08  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+       * tree.h (TYPE_UNQUALIFIED, TYPE_QUAL_CONST): Convert to enum.
+       (TYPE_QUAL_VOLATILE, TYPE_QUAL_RESTRICT): Likewise.
+
 2011-05-09  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/predicates.md (const_pow2_1_to_2_operand): Remove.
index 9bd20b16b84730877cfa2ad87c64aa15ea70920e..17116e00b613ad73c240c1f95cae0caf3a875376 100644 (file)
@@ -1,3 +1,18 @@
+2011-05-08  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+       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  <dodji@redhat.com>
 
        PR c++/48574
index 6b08a038e0b59d2a48d8bce0bc1381c99a4307da..12db2bcb0931c17aa8d9e976c90380cb9cce6cd2 100644 (file)
@@ -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.
index ad298dfd57545abe25db58b264113e3cdb16328d..a03d6a11bcad877b92a2b305fe27171d83f4b845 100644 (file)
@@ -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.  */
index 764d5dffb179cfe59ed5f1e5488e9ea1da4d3fca..c139f3f0ba4642a8d99dd7fc928dd2bf73742d26 100644 (file)
@@ -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.  */
index 82495b65c0a25f12996780d7eee52d1556277988..fa6cd83ed3040b9b47150b1446887e8f21768d8e 100644 (file)
@@ -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
 
index e7d2048e89ffe44c9640bf5d37cd43d1dd0d5160..cf0b1a0a7e01326e3b2a23597277bb8c5f3db459 100644 (file)
@@ -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;
 }
 
index b15dba9b3500550dd4a6a4b846ed86dfc665357b..5b72fc5d6c6cd4529cd597046ddc7a6e620c1221 100644 (file)
@@ -1,3 +1,7 @@
+2011-05-08  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+        * g++.dg/inherit/virtual9.C: New.
+
 2011-05-09  Dodji Seketeli  <dodji@redhat.com>
 
        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 (file)
index 0000000..d3175e1
--- /dev/null
@@ -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 <class T> 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<B> d2;
+  D2<B2> d3;
+}
index d0cd3e05b25e071f5c921384f08624f9bcdbe70f..4cf1730d4cb0b0392d07a83c39551d57d6e8974e 100644 (file)
@@ -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.  */