Patchwork C++0x, implement final on classes

login
register
mail settings
Submitter ville
Date May 13, 2011, 5:24 p.m.
Message ID <87liyav7hf.wl%ville@ville-laptop>
Download mbox | patch
Permalink /patch/95502/
State New
Headers show

Comments

ville - May 13, 2011, 5:24 p.m.
Tested on Linux/X86-32.

2011-05-13 Ville Voutilainen <ville.voutilainen@gmail.com> <ville.voutilainen@symbio.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.
          * cp-tree.h (CLASSTYPE_FINAL): New.
          * parser.c (cp_parser_class_head): Parse class-virt-specifier, set CLASSTYPE_FINAL.
          * pt.c (instantiate_class_template_1): Copy the CLASSTYPE_FINAL.
Jason Merrill - May 13, 2011, 5:46 p.m.
On 05/13/2011 01:24 PM, Ville Voutilainen wrote:
> +        error ("cannot derive from from final base %qT in derived type %qT",

Let's use %<final%> here.

>     if (id)
> -    cp_parser_check_for_invalid_template_id (parser, id,
> -					     type_start_token->location);
> +    {
> +      virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
> +      cp_parser_check_for_invalid_template_id (parser, id,
> +                                               type_start_token->location);
> +    }

Why did you put this before the invalid template-id check, rather than 
after?

Also, shouldn't we reject "override" on classes?

The test should include a class template marked final.

Jason
ville - May 13, 2011, 5:53 p.m.
On 13 May 2011 20:46, Jason Merrill <jason@redhat.com> wrote:
> Why did you put this before the invalid template-id check, rather than
> after?

For no particular reason. Is it significant?

> Also, shouldn't we reject "override" on classes?

You can have stuff like
struct blah override{};

where struct blah is an elaborate-type-specifier, and override is a
variable name.
How do I tell the difference, or more precisely, how do I know when a
class is being defined for
the first time?

> The test should include a class template marked final.

Ok, I'll fix these issues, any guidance for the override question
above is highly appreciated.
Jason Merrill - May 13, 2011, 6:13 p.m.
On 05/13/2011 01:53 PM, Ville Voutilainen wrote:
> On 13 May 2011 20:46, Jason Merrill<jason@redhat.com>  wrote:
>> Why did you put this before the invalid template-id check, rather than
>> after?
>
> For no particular reason. Is it significant?

Yes, the order affects the handling of

struct Undeclared<int> final { };

>> Also, shouldn't we reject "override" on classes?
>
> You can have stuff like
> struct blah override{};
>
> where struct blah is an elaborate-type-specifier, and override is a
> variable name.
> How do I tell the difference, or more precisely, how do I know when a
> class is being defined for the first time?

Add the error after the call to cp_parser_commit_to_tentative_parse, at 
which point we've decided that we're dealing with a class definition.

Jason

Patch

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 293dd1c..44b1d8e 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1268,6 +1268,10 @@  check_bases (tree t,
 
       gcc_assert (COMPLETE_TYPE_P (basetype));
 
+      if (CLASSTYPE_FINAL (basetype))
+        error ("cannot derive from 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;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1705232..901a17d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1321,6 +1321,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
@@ -1329,7 +1330,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;
@@ -1437,6 +1438,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)
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index fa6cd83..5e9b8a8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17117,6 +17117,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 +17261,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);
+    {
+      virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+      cp_parser_check_for_invalid_template_id (parser, id,
+                                               type_start_token->location);
+    }
 
   /* 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
@@ -17493,6 +17497,8 @@  cp_parser_class_head (cp_parser* parser,
   if (type)
     DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
   *attributes_p = attributes;
+  if (virt_specifiers & VIRT_SPEC_FINAL)
+    CLASSTYPE_FINAL (type) = 1;
  out:
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   return type;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5e24977..5e059e0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
 
diff --git a/gcc/testsuite/g++.dg/inherit/base4.C b/gcc/testsuite/g++.dg/inherit/base4.C
new file mode 100644
index 0000000..5736193
--- /dev/null
+++ b/gcc/testsuite/g++.dg/inherit/base4.C
@@ -0,0 +1,23 @@ 
+// { dg-do compile }
+// { dg-options "--std=c++0x" }
+struct B1 {};
+
+struct B2 final {};
+
+struct D1 : B1 {};
+
+struct D2 : B2 {}; // { dg-error "cannot derive from from final base" }
+
+template<class T> struct D3 : T {};
+
+template<class T> struct D4 : T {}; // { dg-error "cannot derive from from final base" }
+
+struct B3 final final {}; // { dg-error "duplicate virt-specifier" }
+
+int main()
+{
+  D3<B1> d;
+  D4<B2> d2;
+  struct B2 final{};
+  struct B1 final2{};
+}