Implement final on class.
authorVille Voutilainen <ville.voutilainen@gmail.com>
Sat, 14 May 2011 18:13:23 +0000 (21:13 +0300)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 14 May 2011 18:13:23 +0000 (14:13 -0400)
* 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

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/override1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/override2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/inherit/virtual9.C [deleted file]

index 9a42e3e3ac89264fa264ee18ff33615a57d99c18..f0371ad8b0164459494d3e942fe979dbe35c7f14 100644 (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>
 
        PR c++/48969
index 938d52201e3e0f2b23023d1f3d17f9d8e67728d1..dc2c509a8cf29feaef4cc905d8f7ab3e158f08ec 100644 (file)
@@ -1268,6 +1268,10 @@ check_bases (tree t,
 
       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 (!CLASSTYPE_LITERAL_P (basetype))
         CLASSTYPE_LITERAL_P (t) = false;
index bcf78f8f14e26aacd9848272e873264dcf4dd6fa..c0b52908883b6924514c0990c17a8a22544bc3c6 100644 (file)
@@ -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)
 
index fa6cd83ed3040b9b47150b1446887e8f21768d8e..a77d4ffb6ac4508b1e2556964e129f5de2a5ad56 100644 (file)
@@ -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 %<override%> 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;
index f155c1ab61d3bacf083cca177a9dd6c041db6da1..e441a706d653b386caa2c8188af0f3068484ef63 100644 (file)
@@ -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);
 
index f014a807532cd3d8e86cb6f49b158762cbf5487b..b7a8f50d593cd31c5eea9cb3dde4ea3a47a3e4ca 100644 (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>
 
        PR fortran/18918
diff --git a/gcc/testsuite/g++.dg/cpp0x/override1.C b/gcc/testsuite/g++.dg/cpp0x/override1.C
new file mode 100644 (file)
index 0000000..83e0479
--- /dev/null
@@ -0,0 +1,60 @@
+// { dg-do compile }
+struct B
+{
+  virtual void f() final {}
+  virtual void g() {}
+  virtual void x() const {}
+};
+
+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" }
+};
+
+template <class T> struct D3 : T
+{
+  void h() override {}
+};
+
+struct D4 : D
+{
+  void g() {} // { dg-error "virtual function" }
+};
+
+struct B3
+{
+  virtual void f() final final {} // { dg-error "duplicate virt-specifier" }
+};
+
+struct B4
+{
+  void f() final {} // { dg-error "marked final, but is not virtual" }
+};
+
+struct D5 : B
+{
+  void ff() override {} // { dg-error "marked override, but does not override" }
+  virtual void fff() override {} // { dg-error "marked override, but does not override" }
+  virtual void x() override {} // { dg-error "marked override, but does not override" }
+  void g() override;
+};
+
+void D5::g() override {} // { dg-error "not allowed outside a class definition" }
+void g() override {} // { dg-error "not allowed outside a class definition" }
+
+int main()
+{
+  D2<B> d;
+  D2<B2> d2;
+  D3<B2> d3;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/override2.C b/gcc/testsuite/g++.dg/cpp0x/override2.C
new file mode 100644 (file)
index 0000000..7f17504
--- /dev/null
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/inherit/virtual9.C b/gcc/testsuite/g++.dg/inherit/virtual9.C
deleted file mode 100644 (file)
index 83e0479..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// { dg-do compile }
-struct B
-{
-  virtual void f() final {}
-  virtual void g() {}
-  virtual void x() const {}
-};
-
-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" }
-};
-
-template <class T> struct D3 : T
-{
-  void h() override {}
-};
-
-struct D4 : D
-{
-  void g() {} // { dg-error "virtual function" }
-};
-
-struct B3
-{
-  virtual void f() final final {} // { dg-error "duplicate virt-specifier" }
-};
-
-struct B4
-{
-  void f() final {} // { dg-error "marked final, but is not virtual" }
-};
-
-struct D5 : B
-{
-  void ff() override {} // { dg-error "marked override, but does not override" }
-  virtual void fff() override {} // { dg-error "marked override, but does not override" }
-  virtual void x() override {} // { dg-error "marked override, but does not override" }
-  void g() override;
-};
-
-void D5::g() override {} // { dg-error "not allowed outside a class definition" }
-void g() override {} // { dg-error "not allowed outside a class definition" }
-
-int main()
-{
-  D2<B> d;
-  D2<B2> d2;
-  D3<B2> d3;
-}