<html>
<head>
<title>P0929R1: Checking for abstract class types</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .new { text-decoration:none; font-weight:bold; background-color:#D0FFD0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }  
  strong { font-weight: inherit; color: #2020ff }
  table, td, th { border: 1px solid black; border-collapse:collapse; padding: 5px }
</style>
</head>

<body>
ISO/IEC JTC1 SC22 WG21 P0929R1<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Target audience: CWG<br/>
2018-03-24<br/>

<h1>P0929R1: Checking for abstract class types</h1>

<h2>Introduction</h2>

Subclause 13.4 [class.abstract] paragraph 3 states:

<blockquote>
An abstract class shall not be used as a parameter type, as a function
return type, or as the type of an explicit conversion. Pointers and
references to an abstract class can be declared.
</blockquote>

This is troublesome, because it requires checking a property only
known once a type is complete at a position (declaring a function)
where the rest of the language permits incomplete types to appear.
<p>
In practice, this introduces spooky "backward-in-time" errors:

<blockquote>
<pre>
struct S;
S f();   // #1, ok

// lots of code

struct S { virtual void f() = 0; };  // makes #1 retroactively ill-formed
</pre>
</blockquote>

<h2>Changes</h2>

Relative to P0929R0:
<ul>
  <li>Treat arrays of abstract class type similarly.</li>
  <li>Update wording.</li>
</ul>

<h2>Discussion</h2>

Declarations should add information to the state of a program, not
retroactively make existing constructs that have been parsed
successfully ill-formed.
<p>
Beyond the ability to declare functions with incomplete return and
parameter types, the standard also allows for the return type to be
inspected using decltype(f()) even if it is incomplete. This ability
might be used in template metaprogramming, and it should not break if
one of the involved types happens to be abstract.
<p>
There are two approaches to solving this issue:
<ul>
  <li>State that a return type or a parameter type is ill-formed if
    it is complete and an abstract class type at the point of
    declaration of the function type.
  </li>
  <li>Never check declarations involving function types whether they
    involve a return type or parameter of abstract class type.
    Instead, postpone the check to the definition and the call, where
    actual objects need to be created, and where the existing text
    already requires completeness of the types involved.
  </li>
</ul>

The first option seems bizarre in that token-by-token identical
redeclarations may become ill-formed:
<blockquote>
  <pre>
    struct S;
    S f();      // ok, abstract-ness not checked here
    struct S { virtual void f() = 0; };
    S f();      // error: S is abstract
  </pre>
</blockquote>

Therefore, the proposed wording chooses the second option.
<p>
It is recommended to treat this as a Defect Report against earlier
versions of C++.
<p>
The suggested feature test macro is <code>__cpp_abstract_class_checking</code>.

<h2>Wording changes</h2>

Change in 6.1 [basic.def] paragraph 15:

<blockquote>
<del>A program is ill-formed if</del> <ins>In</ins> the definition
of</ins> <del>any</del> <ins>an</ins> object <del>gives
the</del><ins>, the type of that</ins> object <ins>shall not be</ins>
an incomplete type (6.7 [basic.types]),<ins>, an abstract class type
(13.4 [class.abstract]), or a (possibly multi-dimensional) array
thereof</ins>.
</blockquote>

Change in 8.2.1 [basic.lval] paragraph 9:

<blockquote>
Unless otherwise indicated (<del>8.5.1.2 [expr.call]</del>
<ins>10.1.7.2 [dcl.type.simple]</ins>), a prvalue shall always have
complete type or the void type<ins>; if it has a class type or
(possibly multi-dimensional) array of class type, that class
shall not be an abstract class (13.4 [class.abstract])</ins>.
</blockquote>


Change in 8.5.1.2 [expr.call] paragraph 4:

<blockquote>
... When a function is called, <del>the parameters that have object
type shall have completely-defined object type</del> <ins>the type of
any parameter shall not be an incomplete or abstract class type</ins>. [
Note: this still allows a parameter to be a pointer or reference to an
incomplete class type. However, it prevents a passed-by-value
parameter to have an incomplete class type. -- end note ] ...
</blockquote>

Change in 11.3.4 [dcl.array] paragraph 1:

<blockquote>
... T is called the <em>array element type</em>; this type shall not
be a reference type, <em>cv</em> <code>void</code>, <ins>or</ins> a
function type <del>or an abstract class type</del>. ...
</blockquote>

Change in 11.3.5 [dcl.fct] paragraph 12:

<blockquote>
Types shall not be defined in return or parameter types. The type of a
parameter or the return type for a function definition shall not be an
incomplete <ins>or abstract</ins> (possibly cv-qualified) class type
in the context of the function definition unless the function is
deleted (11.4.3).
</blockquote>

<em>Editorial note: I suggest to move the statement about function definitions to 11.4 [dcl.fct.def].)</em>

<p>

Change in 12.2 [class.mem] paragraph 14:

<blockquote>
<del>Non-static</del><ins>The type of a non-static</ins>
data <del>members</del><ins>member</ins> shall
not <del>have</del><ins>be an</ins>
incomplete <del>types</del><ins>type (6.7 [basic.types]), an abstract
class type (13.4 [class.abstract]), or a (possibly multi-dimensional)
array thereof</ins>. <ins>[ Note:</ins> In particular, a class C
<del>shall not</del><ins>cannot</ins> contain a non-static member of
class C, but it can contain a pointer or reference to an object of
class C.<ins>-- end note ]</ins>
</blockquote>

Change in 13.4 [class.abstract] paragraph 2:

<blockquote>
<del>An <em>abstract class</em> is a class that can be used only as a
base class of some other class; no objects of an abstract class can be
created except as subobjects of a class derived from it. A class is
abstract if it has at least one <em>pure virtual function</em>. [
Note: Such a function might be inherited: see below. -- end note
]</del> A virtual function is specified <ins>as
a</ins> <em>pure</em> <ins>virtual function</ins> by using
a <em>pure-specifier</em> (12.2) in the function declaration in the
class definition.
<ins> [ Note: Such a function might be inherited: see below. -- end
note ] A class is <ins>an</ins> <em>abstract <ins>class</ins></em> if
it has at least one pure virtual function.  [ Note: An abstract class
can be used only as a base class of some other class; no objects of an
abstract class can be created except as subobjects of a class derived
from it (6.1 [basic.def], 12.2 [class.mem]). -- end note ]</ins>
A pure virtual function need be defined only if called with, or as if
with (15.4), the <em>qualified-id</em> syntax (8.4).
</blockquote>

Remove 13.4 [class.abstract] paragraph 3:

<blockquote>
<del>An abstract class shall not be used as a parameter type, as a function return type, or as the type of an
explicit conversion. Pointers and references to an abstract class can be declared. [ Example:</del>
<pre>
    <del>shape x;                            // error: object of abstract class
    shape* p;                           // OK
    shape f();                          // error
    void g(shape);                      // error
    shape& h(shape&);                   // OK</del>
</pre>
<del>-- end example ]</del>
</blockquote>

Remove 17.9.2 [temp.deduct] paragraph 11 bullet 11:

<blockquote>
<ul>
<li>...</li>
<li><del>Attempting to create a function type in which a parameter
type or the return type is an abstract class type (13.4
[class.abstract]).</del></li>
</ul
</blockquote>
  
</body>
</html>
