The wording below also address core issue 1065 "[[hiding]] with [[override]]".
Drafting notes: There is an ambiguity when parsing supposedly unnamed classes: "struct final { ... } * p" might define an unnamed final class, or it might define a class called "final". When resolving any ambiguity towards "identifier", unnamed classes can't ever be "final".
Add a new paragraph after 2.11 lex.name paragraph 1:
Some identifiers have a special meaning when appearing in a certain context (see table X).Remove section 7.6.4 dcl.attr.final:When referred to in the grammar, these identifiers are used explicitly rather than using the identifier grammar production. Any ambiguity whether a given identifier has a special meaning or not is resolved to interpret the token as a regular identifier.
Identifiers with special meaning override final
Remove in 7.6.5 dcl.attr.override:The attribute-tokenfinal
specifies derivation semantics for a class and overriding semantics for a virtual function. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to class definitions and to virtual member functions being declared in a class definition.
If a class B is marked final and a class D is derived from B the program is ill formed.
If a virtual member function f in some class B is marked final and in a class D derived from B a function D::f overrides B::f, the program is ill-formed.
[ Example: ... ]
Change the grammar in 9 class and the following sentence:The attribute-tokenoverride
asserts that a virtual member function overrides a function in a base class. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to virtual member functions being declared in a class definition.
If a virtual member function f is marked override and does not override (10.3 class virtual) a member function of a base class the program is ill-formed.
The attribute-tokenhiding
asserts that a class member name hides a name in a base class. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to class members being declared in a class definition.
If a class member is markedhiding
and its name does not hide (3.3.10 basic.scope.hiding, 10.2 class.member.lookup) a class member name in a base class the program is ill-formed.
The attribute-tokenbase_check
specifies that overriding and hiding of base members is strictly checked within a class. It shall appear at most once in each attribute-list and no attribute-argument-clause shall be present. The attribute may be applied to a class definition.
In a class definition markedbase_check
, if a virtual member function that is neither implicitly-declared nor a destructor overrides (10.3 class.virtual) a member function of a base class and it is not marked override, the program is ill-formed. Similarly, in such a class definition, if a class member name other than that of an implicitly-declared special member function hides (3.3.10 basic.scope.hiding, 10.2 class.member.lookup) a class member name in a base class and it is not marked hiding, the program is ill-formed. [ Note: a using-declaration makes the potentially hidden name visible, avoiding the need for the hiding attribute. -- end note ] [ Example: ... ]
Add a new paragraph after 9 class paragraph 2:class-head:... A class-virt-specifier-seq shall contain at most one of each class-virt-specifier. A class-specifierclass-key attribute-specifieropt identifieropt base-clauseopt class-key attribute-specifieropt nested-name-specifier identifier base-clauseopt class-key attribute-specifieropt nested-name-specifieropt simple-template-id base-clauseoptclass-key attribute-specifieropt class-head-name class-virt-specifier-seqopt base-clauseopt class-key attribute-specifieropt base-clauseopt class-head-name: nested-name-specifieropt class-name class-virt-specifier-seq: class-virt-specifier class-virt-specifier-seq class-virt-specifier class-virt-specifier: final explicitwhere thewhose class-head omitsthe optional identifierthe class-head-name defines an unnamed class. [ Note: An unnamed class thus can't befinal
orexplicit
. ]
If a class is marked with the class-virt-specifier
final
and it appears as a
base-type-specifier in a base-clause (10
class.derived), the program is ill-formed.
Change 9 class paragraph 10:
If aChange the grammar in 9.2 class.mem:class-headclass-head-name contains a nested-name-specifier, the class-specifier shall refer to a class that was previously declared directly in the class or namespace to which the nested-name-specifier refers, or in an element of the inline namespace set (7.3.1 namespace.def) of that namespace (i.e., not merely inherited or introduced by a using-declaration), and the class-specifier shall appear in a namespace enclosing the previous declaration. In such cases, the nested-name-specifier of theclass-headclass-head-name of the definition shall not begin with a decltype-specifier.
Add two new paragraphs after 9.2 class.mem paragraph 8:member-declarator: declarator virt-specifier-seqopt pure-specifieropt declarator virt-specifier-seqopt brace-or-equal-initializeropt identifieropt attribute-specifieropt virt-specifier-seqopt : constant-expression virt-specifier-seq: virt-specifier virt-specifier-seq virt-specifier virt-specifier: override final new pure-specifier: = 0
A virt-specifier-seq shall contain at most one of each virt-specifier. The virt-specifiersAdd a new paragraph after 10 class.derived paragraph 8:override
andfinal
shall only appear in the declaration of a virtual member function.If a class member is marked
new
and its name does not hide (3.3.10 basic.scope.hiding, 10.2 class.member.lookup) a class member name in a base class the program is ill-formed.
In a class definition marked with the class-virt-specifierAdd two new paragraphs after 10.3 class.virtual paragraph 3:explicit
, if a virtual member function that is neither implicitly-declared nor a destructor overrides (10.3 class.virtual) a member function of a base class and it is not marked with the virt-specifieroverride
, the program is ill-formed. Similarly, in such a class definition, if a class member name other than that of an implicitly-declared special member function hides (3.3.10 basic.scope.hiding, 10.2 class.member.lookup) a class member name in a base class and it is not markednew
, the program is ill-formed, unless the class member is a member function that overrides the corresponding member in the base class. [ Note: a using-declaration makes the potentially hidden name visible, avoiding the need for thenew
marker. -- end note ] [ Example:class B { virtual void some_func(); virtual void f(int); virtual void h(int); void j(int); void k(); typedef B self; }; class D explicit : public B { void sone_func() override; // error: misspelled name void f(int) override; // OK: f implicitly virtual, overrides B::f virtual void f(long) override; // error: non-matching argument type virtual void f(int) const override; // error: non-matching cv-qualification virtual int f(int) override; // error: non-matching return type virtual void g(long); // OK: new virtual function introduced void h(int); // error: h implicitly virtual, but overriding without marker virtual void h(double); // error: hides B::h without marker virtual void h(char *) new; // OK using B::j; int j(double); // OK: not hiding due to "using" void j(int); // OK, despite `obscuring' B::j(int) virtual int j(void) new; // error: not hiding due to "using" int k; // error: hides B::k without marker int m(int) new; // error: no hiding despite marker typedef D self; // error: hides B::self without marker };-- end example ]
If a virtual function f in some class B is marked with the virt-specifierfinal
and in a class D derived from B a function D::f overrides B::f, the program is ill-formed. [ Example:struct B { virtual void f() const final; }; struct D : B { void f() const; // error: D::f attempts to override final B::f };-- end example ]If a virtual function is marked with the virt-specifier
override
and does not override a member function of a base class, the program is ill-formed. [ Example:struct B { virtual void f(int); }; struct D : B { void f(long) override; // error: wrong signature overriding B::f void f(int) override; // ok };-- end example ]