<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<style>
pre {font-family: "Consolas", "Lucida Console", monospace; margin-left:20pt; }
code {font-family: "Consolas", "Lucida Console", monospace; }
pre > i   { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > i  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
pre > em  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > em { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
dl > dt { font-style:italic; }
body { font-family: "Calibri" }

@media (prefers-color-scheme: dark) {
	body { background: #111; color:  #ccc; }
	a { color:  #38f; }
	a:visited { color:  #a4d; }
	.sect { color:  #ccc; }
    del { text-decoration: line-through; color: #EE9999; }
    ins { text-decoration: underline; color: #99EE99; }
    blockquote.std    { color: #ccc; background-color: #2A2A2A;  border: 1px solid #3A3A3A;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #ccc; background-color: #221820;  border: 1px solid #332228;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #ccc; background-color: #182220;  border: 1px solid #223328; padding: 0.5em; }
    table { border: 1px solid #ccc; border-spacing: 0px;  margin-left: auto; margin-right: auto; }
}

@media (prefers-color-scheme: light) {
	body { background:  white; color: black; }
    del { text-decoration: line-through; color: #8B0040; }
    ins { text-decoration: underline; color: #005100; }
    blockquote.std    { color: #000000; background-color: #F1F1F1;  border: 1px solid #D1D1D1;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #000000; background-color: #FFEBFF;  border: 1px solid #ECD7EC;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #000000; background-color: #C8FFC8;  border: 1px solid #B3EBB3; padding: 0.5em; }
    table { border: 1px solid black; border-spacing: 1px;  margin-left: auto; margin-right: auto; }
}


.comment em { font-family: "Calibri"; font-style:italic; }
p.example   { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }
div.poll { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract  { margin-left: 2em; background-color: #F5F6A2;  border: 1px solid #E1E28E; }

p.function    { }
.attribute    { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

.editor { color: #4444BB; font-style: normal; background-color: #DDDDDD; }

tab { padding-left: 4em; }
tab3 { padding-left: 3em; }

.link { float: right; font-family: "Consolas", "Lucida Console", monospace; font-size:80% }


table.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
td.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
table.poll { border: 1px solid black; border-spacing: 0px;  margin-left: 0px; font-style: normal; }

th { text-align: left; vertical-align: top;  padding-left: 0.4em;  /*padding-right: 0.4em; border-bottom:1px dashed;*/ }
td { text-align: left;  padding-left: 0.4em; padding-right: 0.4em; /*border-right:1px dashed; */}
tr { border: solid; border-width: 1px 0; border-bottom:1px solid blue }


.revision   { /*color: #005599;*/ }
.grammar { list-style-type:none }

</style>

<title>Using `this` in constructor preconditions</title>

</head>
<body>  

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td class="header">P3172R0</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td class="header">2024-03-08</td>
  </tr>
  <tr>
    <th>Audience:&nbsp;&nbsp;</th><th> </th><td class="header">SG21</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </th><td class="header">
        <address>Andrzej Krzemieński &lt;akrzemi1 at gmail dot com&gt;</address>
    </td>
  </tr>
</tbody></table>



<h1>Using `this` in constructor preconditions</h1>


<p> <a href="https://isocpp.org/files/papers/P2900R6.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R6]</a>
	(Contracts for C++), while it doesn't state it explicitly, allows the evaluation of 
    member functions in constructor preconditions. Constructor 
	preconditions are evaluated before the execution of the 
	constructor starts, before calling constructors of member 
	and base subobjects, so evaluating member functions at that 
	point is likely to break unless used with caution. 
    This paper proposes two ways to
	address this: either explicitly call this undefined behavior or make 
	it ill-formed.
	</p>


<h2>1. Problem description</h2> 

<p> Constructor preconditions would typically express the constraints
    on function parameters, and reflect the constraints of the subobject's constructors.</p>

<pre>
class X
{
  std::string name;

public:
  explicit X(const char * n)
    pre(name != nullptr)  <em>// evaluated first</em>
    : name{n}             <em>// evaluated second</em>
    {}
};
</pre> 

<p> <a href="https://isocpp.org/files/papers/P2900R6.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R6]</a>
	also in general allows the (potentially implicit) usage of <code>this</code> in class members&rsquo;
	preconditions, to cover common cases like this: 

<pre>
T&amp; container&lt;T&gt;::front()
  pre(!empty());
</pre> 

<p> But combining the two properties cannot work. Analogous observation applies to postconditions of destructors.</p>

<p> Two features in C++ already suffer from a similar problem. The first is calling &mdash; 
    possibly indirectly &mdash; virtual functions in constructors and destructors. In those cases
	the virtual function call mechanism will not be called, skipping the overriding functions,
	and in the worst case we will get a <em>pure virtual function call</em>.</p>
	
<pre>
struct X
{
  virtual void f() = 0;
  void g() { f(); }
  X() { g(); }
};

struct Y : X
{
  void f() override {}
};
</pre>

<p> The second feature observing a similar problem is function-try-blocks.
    It allows you to execute a code in the constructor body, even though member and base
	subobjects may not have been initialized.
	</p>
	
<pre>
struct B
{
  unique_ptr&lt;int&gt; p;
  <em>// invariant: p != nullptr</em>

  B() {
    throw "error"; <em>// failure during initialization</em>
    p = make_unique&lt;int&gt;(1); 
  }
};

struct D : B
{
  D() 
  try {}
  catch (...) {
    cout &lt;&lt; *p; <em>// initialized or not?</em>
  }
};
</pre>
    
<p> Referring to any non-static member or base class of an object in the handler 
    for a <em>function-try-block</em> of a constructor or destructor for that object results 
    in undefined behavior (<a href="http://eel.is/c++draft/except.handle#10">[except.handle]/10</a>).
    </p>
	
	
<h2>2. Solutions</h2>

<h3>2.1. Undefined behavior</h3>

<p> The first possible solution is to do what C++ currently does for virtual
    functions and function-try-blocks: just <em>trust the user</em> that they will not
    do the dangerous things. In other words, make it undefined behavior when a precondition
    in a constructor or a postcondition in a destructor of object <code>X</code>
    refers to any non-static member or base class of <code>X</code>, or does anything else interacting
	with the construction/destruction process.
    This allows users that know what they are doing to express preconditions on constructors
	in rare cases where this actually makes sense. One such example has been provided by 
	Gašper Ažman</p> 	

<pre>
template &lt;class FullType&gt;
struct MixinA
{
  int size() const;
};

template &lt;typename FullType&gt;
struct MixinB
{
  MixinB()
    pre(static_cast&lt;FullType const&amp;&gt;(*this).size() &gt; 0);    
};

struct FT : MixinA&lt;FT&gt;, MixinB&lt;FT&gt;
{};
</pre>

<p> Here <code>MixinB</code> is aware of the existence of <code>MixinA</code> and that <code>MixinA</code>
    will have been initialized before the constructor of <code>MixinB</code> starts. We only access <code>*this</code>
	to access a fully constructed subobject.
	</p>

<p> It should be noted that the above scheme could be refactored so that <code>MixinB</code> 
    receives a reference to <code>MixinA</code> in the constructor, and then the implicit reference to <code>*this</code>
	could be avoided. But the general point still holds. 
	</p>

<p> Another motivating example, that one would expect to work fine, by Joshua Berne:</p>

<pre>
class SelfRegistering
{
public:
  SelRegistering()
    pre( !Registry::isRegistered(this) )
    post( Registry::isRegistered(this) );

  ~SelfRegistry()
    pre( Registry::isRegistered(this) )
    post( !Registry::isRegistered(this));
};
</pre>

<p> Yet another example, by Lisa Lippincott, is for a class used for cryptography, representing a secret,
    to check in a constructor precondition if its storage is allocated in a dedicated secure partition,
    and to check in the destructor postcondiiton that the storeage (not value) has been zeroed out.
    </p>


<p> Currently C++ has two level of "strictness" when defining the behavior of using objects during construction. 
    A stricter level applies until all base class subobjects have been initialized. A less strict one applies
	after all the base class subobjects have been initialized:</p>

<pre>
struct D : B1, B2
{
  M m1, m2;
  auto f(X x);
  
public:
  D(X x)
    : B1(f(x))   <em> // UB</em>	
    , B2(f(x))   <em> // UB</em>	
                 <em> // &lt;-- less strict part starts</em>	
    , m1(f(x))   <em> // not UB</em>	
    , m2(f(x))   <em> // not UB</em>	
  {}
}; 
</pre>
	
	
<h3>2.2. Ill-formed to use <code>this</code> in any way</h3>

<p> Another possibility is to statically detect if the predicate in the precondition of a constructor
    or a postcondition in the destructor refers to <code>this</code>, even implicitly,
	and make such programs ill-formed. This includes things like <code>sizeof(*this)</code>
	or capturing <code>this</code> in a lambda.
	This has the potential to ban technically valid assertions
	that only need to read the address of the object but not its state.</p>

<p>	Overall, however, this option seems
	a solution more in the spirit of the contracts design: do not introduce new reasons for
	undefined behavior. We already constrained what you can do in a predicate expression:
	names are implicitly <code>const</code> which prevents calling a lot of functions
	that you would be able to call in normal expressions.
	</p>
	
<p> While going with undefined behavior is a necessity for function-try-blocks 
    (in the <code>try</code>-block we just have to allow any statement, 
    and cannot arbitrarily filter them out), in the context of contract assertion,
	which are a separate feature with its own specific rules, we can afford 
	to go the "ill-formed" way.
	</p>  

<p> The contracts implementation in GCC 13 disallows the usage of <code>this</code> specifier in 
    constructor preconditions and destructor postconditions. 
	(See <a href="https://godbolt.org/z/nr3M5T6nT">this Compiler Explorer example</a>.) 
    </p>	
	
<p> It should be noted that while most of the UB cases could be turned into ill-formed programs,
    some situations (e.g., when we obtain the pointer to our object by other means than 
	<code>this</code>) cannot be statically enforced and will have to remain UB.
	</p>


<h3>2.3. Ill-formed to call subobject non-static member functions</h3>

<p> This is a less restrictive version of 2.2 above that allows operating on the address <code>this</code>
    but still prevents things that clearly read the object state: invoking non-static member functions 
	on base and member subobjects.</p>
	
<p> The only problem with it is that it is not implementable. You cannot detect the 
    invocation of a member function that is hidden behind another function call:</p>
	
<pre>
void f(struct X* x); <em>// mystery</em>

struct X
{
  X() 
    pre(f(this))     <em>// reads object state?</em>
    ;
};
</pre>	

<p> The specification for <em>function-try-block</em> can afford to only constrain
    referring to non-static member functions of subobjects, because it calls it undefined behavior,
	and for that no compiler checking is required.
    </p>



<h2>3. Proposal</h2>

<p> This paper does not state a preference between options 2.1 and 2.2.
    Instead we would like SG21 to chose which one is preferred.
	</p>
 
<h2>4. Wording</h2>
 
<p>	We provide wording for both options 2.1 and 2.2. The proposed wording is
    relative to the wording proposed in <a href="https://isocpp.org/files/papers/P2900R6.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R6]</a>.
	</p>

	
<h3>4.1. Wording for the undefined behavior case</h3>


<p> Modify <a href="http://eel.is/c++draft/class.base.init#16">[class.base.init]/16</a> as follows.</p>

<blockquote class="std">

<p> Member functions (including virtual member functions, <a href="http://eel.is/c++draft/class.virtual">[class.virtual]</a>)</del>
    can be called for an object under construction or under destruction.
    Similarly, an object under construction can be the operand of the <code>typeid</code> operator 
    (<a href="http://eel.is/c++draft/expr.typeid">[expr.typeid]</a>) or of a <code>dynamic_cast</code>
    (<a href="http://eel.is/c++draft/expr.dynamic.cast">[expr.dynamic.cast]</a>).
    However, if these operations are performed</p>

    <ul>
        <li>in a <code><em>ctor-initializer</em></code> (or in a function called directly or 
            indirectly from a <code><em>ctor-initializer</em></code>) 
            before all the <code><em>mem-initializers</em></code> for base classes have completed,<ins> or</ins> 
            </li>
        <li><ins>in a precondition assertion of the constructor, or</ins></li>
        <li><ins>in a postcondition assertion of the destructor,</ins></li>
    </ul>    
    the program has undefined behavior.
</p>

</blockquote>


<p> Modify <a href="http://eel.is/c++draft/class.cdtor#1">[class.cdtor]/1</a> as follows.</p>

<blockquote class="std">

<p> For an object with a non-trivial constructor, referring to any non-static member 
    or base class of the object before the constructor begins execution results in undefined behavior.
	<ins>[<em>Note:</em> The evaluation of a constructor precondition assertion is
	considered part of constructor execution. <em>&mdash; end note</em>]</ins>
    For an object with a non-trivial destructor, referring to any non-static member
	or base class of the object after the destructor finishes execution results in undefined behavior.
	<ins>[<em>Note:</em> The evaluation of a destructor postcondition assertion is
	considered part of destructor execution. <em>&mdash; end note</em>]</ins>
    </p>
	
</blockquote>

<p> Modify <a href="http://eel.is/c++draft/class.cdtor#4">[class.cdtor]/4</a> as follows.</p>
        
<blockquote class="std">

    <p>
        Member functions, including virtual functions
        (<a href="http://eel.is/c++draft/class.virtual">[class.virtual]</a>),
        can be called during construction or destruction
        (<a href="http://eel.is/c++draft/class.base.init">[class.base.init]</a>)
        <ins>
            and while evaluating a function contract assertion [dcl.contract.func]
        </ins>.
        When a virtual function is called directly or indirectly from a
        constructor or from a destructor, including during the construction
        or destruction of the class's non-static data members<ins>
        or during the evaluation of a postcondition assertion of a constructor
        or a precondition assertion of a destructor [dcl.contract.func]</ins>,
        and the object
        to which the call applies is the object (call it <code>x</code>) under construction
        or destruction, the function called is the final overrider in the
        constructor's or destructor's class and not one overriding it in
        a more-derived class.
        If the virtual function call uses an explicit class member access
        (<a href="http://eel.is/c++draft/expr.ref">[expr.ref]</a>)
        and the object expression refers to the complete object
        of <code>x</code> or one of that object's base class subobjects
        but not <code>x</code> or one of
        its base class subobjects, the behavior is undefined.
    </p>
	
</blockquote>



<h3>4.2. Wording for the ill-formed case</h3>

<p> Apply all the changes from 4.1.</p>

<p> Modify [dcl.contract.funct] as follows.</p>

<blockquote class="std">

<p> <ins>The predicate of a precondition assertion of a constructor shall not reference
    <code>this</code> or the <code>*this</code> object explicitly or implicitly.
    The predicate of a postcondition assertion of a destructor shall not reference 
    <code>this</code> or the <code>*this</code> object explicitly or implicitly.</ins>
    </p>

<p> When a set of function contract assertions are <em>evaluated in sequence</em>,
    for any two function contract assertions <em>X</em> and <em>Y</em> in the set, 
	the evaluation of <em>X</em> is sequenced before the
    evaluation of <em>Y</em> if the <em><code>function-contract-specifier</code></em> 
	introducing <em>X</em> lexically precedes the one introducing <em>Y</em>.
	</p>

</blockquote>



<h2>5. Acknowledgments</h2>

<p> Peter Brett observed this gap in the specification of contracts and suggested the wording changes
    for the case 2.1.
    </p>

<p> Joshua Berne reviewed the document and suggested wording changes.</p>

<p> Jens Maurer and Gašper Ažman reviewed the document, and contributed to its quality.
    </p>


<h2>6. References</h2>


<ul>
<li>[P2900R6] &mdash; Joshua Berne, Timur Doumler, Andrzej Krzemieński
    "Contracts for C++", <br>
    (<a href="https://isocpp.org/files/papers/P2900R6.pdf">"https://isocpp.org/files/papers/P2900R6.pdf"</a>).
    </li>
    <!--
    <a href="https://isocpp.org/files/papers/P2900R6.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R6]</a>
    -->
</ul>



</body></html>
