* 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
+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
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;
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
/* 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;
#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)
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]
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;
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
/* 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)
{
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;
CLASSTYPE_VISIBILITY_SPECIFIED (type) = 1;
CLASSTYPE_VISIBILITY (type) = CLASSTYPE_VISIBILITY (pattern);
}
+ CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
pbinfo = TYPE_BINFO (pattern);
+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
--- /dev/null
+// { 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;
+}
--- /dev/null
+// { 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" }
+}
+++ /dev/null
-// { 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;
-}