@@ -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;
@@ -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)
@@ -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;
@@ -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);
new file mode 100644
@@ -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{};
+}