<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">

<title>Not so Trivial Issues with Trivial</title>
</head>

<body>
<h1>Not so Trivial Issues with Trivial</h1>

<p>
ISO/IEC JTC1 SC22 WG21 N2762 = 08-0272 - 2008-09-18
</p>

<p>
Lawrence Crowl, Lawrence@Crowl.org, crowl@google.com
<br>
Jens Maurer, Jens.Maurer@gmx.net
<br>
William Michael Miller
</p>

<p>
This document is a revision of N2749 = 08-0259 - 2008-08-24.
It merges in core issue 509
"Dead code in the specification of default initialization".
The issue 509 edits
removes duplicate wording
and merges it into the definition of "default initialization".
</p>


<h2>Problem</h2>

<p>
The original formulation of deleted functions
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2210.htm">N2210</a>)
defined
deleted special member functions to be trivial.
The intent was to not change the efficiency features
associated with trivial types
simply because use of a function is prohibited.
However, the adopted formulation
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2346.htm">N2346</a>)
made deleted special member functions non-trivial.
</p>

<p>
The consequence of non-trivial deleted functions
is that many desirable efficiency features defined for trivial types
no longer apply.
For example, deleting a default constructor made a class non-trivial,
which in turn no longer guaranteed static initialization.
Indeed, there is no reason that a non-deleted, non-trivial default constructor
should necessarily affect static initialization either.
The problem extends to other features,
including object lifetime, parameter passing, and <code>memcpy</code>.
</p>

<p>
The core of the problem is that
many features are defined for trivial types
when they generally rely on only a subset of the attributes
that define a trivial type.
</p>

<h2>Solution</h2>

<p>
We propose to redefine those features
that are defined with trivial types
to be defined with the set of attributes crucial to the feature.
Features already defined directly in terms of attributes
need no change.
This proposal is a continuation in the work of decomposing POD types
and their features
that began with
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2342.htm">N2342
POD's Revisited; Resolving Core Issue 568 (Revision 5)</a>.
</p>

<p>
In our solution,
we introduce the notion of a trivially copyable type.
We then apply this notion in several places.
We have chosen a conservative definition for trivally copyable;
at lease one weaker form exists.
</p>

<p>
With the introduction of trivally copyable types,
and the redefinition of features on type attributes,
there are very few remaining uses of trivial types in the standard.
We recommend that any new uses be very carefully considered
and weaker types are likely to be preferable.
</p>

<p>
Several core-language issues are closely related.
A full resolution of the problems requires resolving these issues as well.
These issues are resolved by
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2757.html">N2757</a>
or this paper.
</p>
<ul>
<li>
509. Dead code in the specification of default initialization
</li>
<li>
684. Constant expressions involving the address of an automatic variable
</li>
<li>
688. Constexpr constructors and static initialization
</li>
</ul>

<p>
We note that the term "trivial default constructor" (12.1p5)
used to imply "no user-declared constructor at all"
(other than the copy constructor),
because otherwise the default constructor
would not have been implicitly declared.
And not being implicitly declared,
must necessarily have been user-defined
and hence not trivial.
However, with the arrival of defaulted functions that retain their triviality,
this is no longer the case.
Singling out default constructors as "trivial"
and assigning special semantics
seems non-intuitive given that
any number of other constructors may be defined
and used to initialize an object.
</p>


<h2>Specific cases</h2>

<p>
In summary, we propose the following changes to the standard.
</p>

<dl>

<dt>1.8p5 intro.object:</dt>
<dd>
The presence or absence of user-defined constructors
appears not to be material for the "continuous bytes of storage" requirement,
but the presence or absence of virtual functions and virtual base classes
may be material.
Out of an abundance of caution,
the other trivial member function restrictions are retained.
</dd>

<dt>3.8 basic.life:</dt>
<dd>
When accessing (parts of) out-of-lifetime objects,
the implementation concern is
accessing objects with virtual base classes and virtual functions,
where the necessary environment setup in the object (e.g. the vtable pointer)
may not be available (either not yet or no longer).
We restrict the undefined behavior to these cases.
</dd>

<dt>3.9p2,3,4 basic.types:</dt>
<dd>
<code>memcpy</code> provisions and value representations
are only concerned with copying and assignment of objects,
but not with the issue how an object obtained its initial value.
The presence or absence of user-defined constructors
will not make a difference.
</dd>

<dt>5.2.2 expr.call:</dt>
<dd>
Passing an object to the ellipsis in a function call
is only a problem if the object's copy contruction or destruction
is non-trivial,
because neither special member function
may actually get called for lack of C++ housekeeping in ellipsis functions.
</dd>

<dt>6.7 stmt.dcl:</dt>
<dd>
Jumping over the definition of an automatic variable
will pose the problem of whether
the destructor for that variable should be run at the end of the block.
Thus, the destructor needs to be trivial, i.e. have no effect.
Similarly, the default constructor
(the one potentially used to initialize the object)
is also required to not do anything, i.e. be trivial.
No other requirements are necessary.
</dd>

<dt>8.5p5 dcl.init:</dt>
<dd>
Core issue 509 will perform major changes in default initialization,
which will benefit the cause of this paper.
</dd>

<dt>12.7p1 class.cdtor:</dt>
<dd>
Similar to the lifetime rules in 3.8
(which may be redundant with this provision),
only the specific special member function being executed is inspected.
</dd>

<dt>25.4p4 alg.c.library:</dt>
<dd>
<code>qsort</code> should only be concerned
with copying and potentially destruction, not initial values.
So limiting the realm of undefined behavior in this case
should not be a problem.
</dd>

</dl>


<h2>Wording</h2>


<h3>1.8 The C++ object model [intro.object]</h3>

<p>
Edit paragraph 5 as follows.
</p>

<blockquote>
<p>
An object of <del>trivial</del> <ins>trivially copyable</ins>
or standard-layout type (3.9)
shall occupy contiguous bytes of storage.
</p>
</blockquote>


<h3>3.8 Object Lifetime [basic.life]</h3>

<p>
Edit paragraph 2 as follows.
</p>

<blockquote>
<p>
[<i>Note:</i>
the lifetime of an array object
<del>or of an object of trivial type (3.9)</del>
starts as soon as storage with proper size and alignment is obtained,
and its lifetime
ends when the storage which the array <del>or object</del> occupies
is reused or released.
12.6.2 describes the lifetime of base and member subobjects.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Edit paragraph 5 as follows.
</p>

<blockquote>
<p>
Before the lifetime of an object has started
but after the storage which the object will occupy
has been allocated<sup>35)</sup>
[<i>Footnote:</i>
For example,
before the construction of a global object of non-POD class type (12.7).
&mdash;<i>end footnote</i>]
or,
after the lifetime of an object has ended
and before the storage which the object occupied is reused or released,
any pointer that refers to the storage location
where the object will be or was located
may be used but only in limited ways.
Such a pointer refers to allocated storage (3.7.3.2),
and using the pointer as if the pointer were of type <code>void*</code>,
is well-defined.
Such a pointer may be dereferenced
but the resulting lvalue may only be used in limited ways,
as described below.
<del>If the object will be or was of a class type with a non-trivial destructor,
and the pointer is used as the operand of a <var>delete-expression</var>,
the program has undefined behavior.</del>
<del>If the object will be or was of a non-trivial class type,
the</del> <ins>The</ins> program has undefined behavior if:
</p>
<ul>
<li>
<ins>the object will be or was of a class type with a non-trivial destructor,
and the pointer is used as the operand of a <var>delete-expression</var>,</ins>
</li>
<li>
the pointer is used to access a non-static data member
or call a non-static member function of the object,
or
</li>
<li>
the pointer is implicitly converted (4.10) to a pointer to a base class type,
or
</li>
<li>
the pointer is used as the operand of a <code>static_cast</code> (5.2.9)
(except when the conversion is to <code>void*</code>, or to <code>void*</code>
and subsequently to <code>char*</code>, or <code>unsigned char*</code>).
</li>
<li>
the pointer is used as the operand of a <code>dynamic_cast</code> (5.2.7)
[<i>Example:</i> .... <i>end example</i>]
</li>
</ul>
</blockquote>

<p>
Edit paragraph 6 as follows.
</p>

<blockquote>
<p>
Similarly, before the lifetime of an object has started
but after the storage which the object will occupy has been allocated or,
after the lifetime of an object has ended
and before the storage which the object occupied is reused or released,
any lvalue which refers to the original object may be used
but only in limited ways.
Such an lvalue refers to allocated storage (3.7.3.2),
and using the properties of the lvalue
which do not depend on its value is well-defined.
<del>If an lvalue-to-rvalue conversion (4.1) is applied to such an lvalue,
the program has undefined behavior;</del>
<del>if the original object will be or was of a non-trivial class type,
the</del> <ins>The</ins> program has undefined behavior if:
</p>
<ul>
<li>
<ins>an lvalue-to-rvalue conversion (4.1) is applied to such an lvalue,</ins>
</li>
<li>
the lvalue is used to access a non-static data member
or call a non-static member function of the object, or
</li>
<li>
the lvalue is implicitly converted (4.10) to a reference to a base class type,
or
</li>
<li>
the lvalue is used as the operand of a <code>static_cast</code> (5.2.9)
except when the conversion
is ultimately to <var>cv</var> <code>char&amp;</code>
or <var>cv</var> <code>unsigned char&amp;</code>, or
</li>
<li>
the lvalue is used as the operand of a <code>dynamic_cast</code> (5.2.7)
or as the operand of typeid.
</li>
</ul>
</blockquote>


<h3>3.9 Types [basic.types]</h3>

<p>
Edit paragraph 2 as follows:
</p>

<blockquote>
<p>
For any object (other than a base-class subobject)
of <del>trivial</del> <ins>trivially copyable</ins> type <code>T</code>,
whether or not the object holds a valid value of type <code>T</code>,
the underlying bytes (1.7) making up the object
can be copied into an array of char or unsigned char.<sup>36)</sup>
If the content of the array of char or unsigned char
is copied back into the object,
the object shall subsequently hold its original value.
</p>
</blockquote>

<p>
Edit paragraph 3 as follows:
</p>

<blockquote>
<p>
For any <del>trivial</del> <ins>trivially copyable</ins> type <code>T</code>,
if two pointers to <code>T</code>
point to distinct <code>T</code> objects
<code>obj1</code> and <code>obj2</code>,
where neither <code>obj1</code> nor <code>obj2</code> is a base-class subobject,
if the value of <code>obj1</code> is copied into <code>obj2</code>,
using the <code>std::memcpy</code> library function,
<code>obj2</code> shall subsequently hold the same value as <code>obj1</code>.
[<i>Example:</i>
</p>
<pre>
<code>T* t1p;</code>
<code>T* t2p;</code>
<em>// provided that <code>t2p</code> points to an initialized object ...</em>
<code>std::memcpy(t1p, t2p, sizeof(T));</code>
<em>// at this point, every subobject of <del>trivial</del> <ins>trivially copyable</ins> type in <code>*t1p</code> contains</em>
<em>// the same value as the corresponding subobject in <code>*t2p</code></em>
</pre>
<p>
&mdash;<i>end example</i>]
</p>
</blockquote>

<p>
Edit paragraph 4 as follows:
</p>

<blockquote>
<p>
The <dfn>object representation</dfn> of an object of type <code>T</code>
is the sequence of <code>N unsigned char</code> objects
taken up by the object of type <code>T</code>,
where <code>N</code> equals <code>sizeof(T)</code>.
The value representation of an object
is the set of bits that hold the value of type <code>T</code>.
For <del>trivial</del>
<ins>trivially copyable</ins> types,
the value representation is a set of bits in the object representation
that determines a value,
which is one discrete element of an implementation-defined set of values.
[<i>Footnote:</i>
The intent is that the memory model of C++
is compatible with that of ISO/IEC 9899 Programming Language C.
&mdash;<i>end footnote</i>]
</p>
</blockquote>

<p>
Edit paragraph 9 as follows.
</p>

<blockquote>
<p>
Arithmetic types (3.9.1), enumeration types, pointer types,
pointer to member types (3.9.2), and <code>std::nullptr_t</code>,
and <var>cv-qualified</var> versions of these types (3.9.3)
are collectively called <dfn>scalar types</dfn>.
Scalar types, POD classes (clause 9), arrays of such types
and <var>cv-qualified</var> versions of these types (3.9.3)
are collectively called <dfn>POD types</dfn>.
<ins>Scalar types, trivially copyable class types (clause 9),
arrays of such types
and cv-qualified versions of these types (3.9.3)
are collectively called <dfn>trivially copyable types</dfn>.</ins>
Scalar types, trivial class types (clause 9),
arrays of such types
and cv-qualified versions of these types (3.9.3)
are collectively called <dfn>trivial types</dfn>.
Scalar types, standard-layout class types (clause 9),
arrays of such types
and cv-qualified versions of these types (3.9.3)
are collectively called <dfn>standard-layout types</dfn>.
</p>
</blockquote>

<h3>5.2.2 Function call [expr.call]</h3>

<p>
Edit paragraph 7 as follows.
</p>

<blockquote>
<p>
...
Passing an argument of <del>non-trivial</del> class type (clause 9)
<ins>with a non-trivial copy constructor or a non-trivial destructor</ins>
with no corresponding parameter
is conditionally-supported,
with implementation-defined semantics.
...
</p>
</blockquote>


<h3>5.3.4 New [expr.new]</h3>

<p>
Edit paragraph 16 as follows.
This edit arises from issue 509.
</p>

<blockquote>
<p>
A <dfn>new-expression</dfn>
that creates an object of type <code>T</code>
initializes that object as follows:
</p>
<ul>
<li>If the <var>new-initializer</var> is omitted<del>:</del><ins>,
the object is default-initialized (8.5 dcl.init);
if no initialization is performed, the object has indeterminate value.</ins>
<ul>
<li>
<del>If <code>T</code> is a (possibly cv-qualified)
non-trivial class type (or array thereof),
the object is default-initialized (8.5).</del>
<del>If <code>T</code> is a const-qualified type,
the underlying class type shall have a user-provided default constructor.</del>
</li>
<li>
<del>Otherwise, the object created has indeterminate value.
If <code>T</code> is a const-qualified type,
or a (possibly cv-qualified) trivial class type (or array thereof)
containing (directly or indirectly) a member of const-qualified type,
the program is ill-formed;</del>
</li>
</ul>
</li>
<li>...</li>
</ul>
</blockquote>


<h3>5.19 Constant expressions [expr.const]</h3>

<p>
Edit paragraph 2 as follows.
Note that issue 684 will make non-conflicting edits to this paragraph.
</p>

<blockquote>
<p>
A <dfn>conditional-expression</dfn> is a constant expression
unless it involves one of the following
as a potentially evaluated subexpression (3.2),
but subexpressions of
logical AND (5.14), logical OR (5.15), and conditional (5.16) operations
that are not evaluated are not considered
[<i>Note:</i>
an overloaded operator invokes a function
&mdash;<i>end note</i>]:
</p>

<ul>
<li>...</li>
<li>
a class member access (5.2.5)
unless its postfix-expression is of <del>trivial or</del> literal type
or of pointer to <del>trivial or</del> literal type;
</li>
<li>...</li>
</ul>
</blockquote>


<h3>6.7 Declaration statement [stmt.dcl]</h3>

<p>
Edit paragraph 3 as follows:
</p>

<blockquote>
<p>
It is possible to transfer into a block,
but not in a way that bypasses declarations with initialization.
A program that jumps<sup>78)</sup>
from a point where a local variable with automatic storage duration
is not in scope
to a point where it is in scope
is ill-formed unless the variable has <del>trivial type (3.9)</del>
<ins>scalar type,
class type with a trivial default constructor and a trivial destructor,
a cv-qualified version of one of these types, or
an array of one of the preceding types</ins>
and is declared without an <var>initializer</var> (8.5).
</p>
</blockquote>


<h3>8.5 Initializers [dcl.init]</h3>

<p>
Edit paragraph 5 as follows,
splitting paragraph 5 into three paragraphs,
one for each kind of initialization.
The majority of this edit arises from issue 509.
</p>

<blockquote>
<p>
To <dfn>zero-initialize</dfn> an object <ins>or reference</ins>
of type <code>T</code> means:
<ul>
<li>
<del>if T is std::nullptr_t, the object is set to the value of nullptr;</del>
</li>
<li>
<del>otherwise,</del> if <code>T</code> is a scalar type (3.9),
the object is set to the value <code>0</code> (zero),
taken as an integral constant expression, converted to <code>T</code>;
[<i>Footnote:</i>
As specified in 4.10,
converting an integral constant expression whose value is <code>0</code>
to a pointer type results in a null pointer value.
&mdash;<i>end footnote</i>]
</li>
<li>
if <code>T</code> is a <ins>(possibly cv-qualified)</ins> non-union class type,
each non-static data member and each base-class subobject is zero-initialized;
</li>
<li>
if <code>T</code> is a <ins>(possibly cv-qualified)</ins> union type,
the object's first <ins>non-static</ins> named data member
<del>[<i>Footnote:</i>
This member must not be static, by virtue of the requirements in 9.5.
&mdash;<i>end footnote</i>]</del>
is zero-initialized;
<li>
if <code>T</code> is an array type, each element is zero-initialized;
</li>
<li>
if <code>T</code> is a reference type, no initialization is performed.
</li>
</ul>
</blockquote>

<blockquote>
<p>
To <dfn>default-initialize</dfn> an object of type <code>T</code> means:
</p>
<ul>
<li>
if <code>T</code> is a <ins>(possibly cv-qualified)</ins>
<del>non-trivial</del> class type (clause 9),
the default constructor for <code>T</code> is called
(and the initialization is ill-formed
if <code>T</code> has no accessible default constructor);
</li>
<li>
if <code>T</code> is an array type, each element is default-initialized;
</li>
<li>
otherwise, <del>the object is zero-initialized</del>
<ins>no initialization is performed</ins>.
</li>
</ul>
<p>
<ins>If a program calls for
the default initialization of
an object of a const-qualified type <code>T</code>,
<code>T</code> shall be a class type
with a user-provided default constructor.</ins>
</p>
</blockquote>

<blockquote>
<p>
To <dfn>value-initialize</dfn> an object of type <code>T</code> means:
</p>
<ul>
<li>
if <code>T</code> is a <ins>(possibly cv-qualified)</ins> class type (clause 9)
with a user-provided constructor (12.1),
then the default constructor for <code>T</code>
is called
(and the initialization is ill-formed
if <code>T</code> has no accessible default constructor);
</li>
<li>
if <code>T</code> is a <ins>(possibly cv-qualified)</ins> non-union class type
without a user-provided constructor,
then <del>every non-static data member
and base-class component of <code>T</code>
is value-initialized;
[<i>Footnote:</i>
Value-initialization for such a class object
may be implemented by zero-initializing the object
and then calling the default constructor.
&mdash;<i>end footnote</i>]</del>
<ins>the object is zero-initialized and,
if <code>T</code>'s implicitly-declared default constructor is non-trivial,
that constructor is called.</ins>
</li>
<li>if <code>T</code> is an array type,
then each element is value-initialized;
</li>
<li>
otherwise, the object is zero-initialized<ins>.</ins>
</li>
</ul>
</blockquote>

<p>
Edit paragraph 6 as follows,
This edit arises from issue 509.
</p>

<blockquote>
<p>
A program that calls for default-initialization or value-initialization
of an entity of reference type
is ill-formed.
<del>If <code>T</code> is a cv-qualified type,
the cv-unqualified version of <code>T</code> is used
for these definitions of zero-initialization, default-initialization,
and value-initialization.</del>
</p>
</blockquote>

<p>
Edit paragraph 7 as follows,
This edit arises from issue 509.
</p>

<blockquote>
<p>
<ins>[<i>Note:</i></ins>
Every object of static storage duration
shall be zero-initialized at program startup
before any other initialization takes place.
<del>[<i>Note:</i>
in</del> <ins>In</ins> some cases,
additional initialization is done later.
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Edit paragraph 9 as follows.
The majority of this edit arises from issue 509.
</p>

<blockquote>
<p>
If no initializer is specified for an object,
<ins>the object is default-initialized;
if no initialization is performed, a non-static object has indeterminate value.
[<i>Note:</i>
Objects with static storage duration are zero-initialized,
see 3.6.2 basic.start.init.
&mdash;<i>end note</i>]</ins>
<del>and the object is of (possibly cv-qualified) non-trivial class type
(or array thereof),
the object shall be default-initialized;
if the object is of const-qualified type,
the underlying class type shall have a user-provided default constructor.
Otherwise, if no initializer is specified for a non-static object,
the object and its subobjects, if any,
have an indeterminate initial value<sup>95)</sup>
[<i>Footnote:</i>
This does not apply to aggregate objects
with automatic storage duration
initialized with an incomplete brace-enclosed initializer-list;
see 8.5.1 dcl.init.aggr.
&mdash;<i>end footnote</i>];
if the object or any of its subobjects are of const-qualified type,
the program is ill-formed.</del>
</p>
</blockquote>


<h3>Chapter 9 Classes [class]</h3>

<p>
Edit paragraph 5 as follows.
Note that this edit is subsequent to the application of
the edits in core issue 683 in
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2757.html">N2757</a>.
</p>

<blockquote>
<p>
<ins>A <dfn>trivially copyable class</dfn> is a class that:</ins>
</p>
<ul>
<li><ins>has no non-trivial copy constructors (12.8),</ins></li>
<li><ins>has no non-trivial copy assignment operators (13.5.3, 12.8),
and</ins></li>
<li><ins>has a trivial destructor (12.4).</ins></li>
</ul>
<p>
A <dfn>trivial class</dfn> is a class that:
</p>
<ul>
<li>has a trivial default constructor (12.1),
<ins>and</ins></li>
<li><del>has no non-trivial copy constructors (12.8),</del></li>
<li><del>has no non-trivial copy assignment operators (13.5.3, 12.8),
and</del></li>
<li><del>has a trivial destructor (12.4).</del></li>
<li><ins>is trivially copyable.</ins></li>
</ul>
<p>
[<i>Note:</i>
in particular, a <ins>trivially copyable or </ins> trivial class
does not have virtual functions or virtual base classes.
&mdash;<i>end note</i>]
</p>
</blockquote>


<h3>9.5 Unions [class.union]</h3>

<p>
Within paragraph 1 edit as follows.
</p>

<blockquote>
<p>
...
[<i>Note:</i>
If any non-static data member of a union
has a non-trivial default constructor (12.1),
copy constructor (12.8), copy assignment operator (12.8), or destructor (12.4),
the corresponding member function of the union must be
<del>user-declared</del> <ins>user-provided</ins>
or it will be implicitly deleted (8.4) for the union. 
&mdash;<i>end note</i>]
</p>
</blockquote>


<h3>12.4 Destructors [class.dtor]</h3>

<p>
Edit paragraph 3 as follows.
</p>

<blockquote>
<p>
If a class has no user-declared destructor,
a destructor is declared implicitly.
An implicitly-declared destructor
is an <code>inline public</code> member of its class.
If the class is a union-like class
that has a variant member with a non-trivial destructor,
an implicitly-declared destructor is defined as deleted (8.4).
A destructor is trivial if it is not user-provided and if:
</p>

<ul>
<li>
<ins>the destructor is not <code>virtual</code>,</ins>
</li>

<li>
all of the direct base classes of its class
have trivial destructors<ins>,</ins> and
</li>

<li>
for all of the non-static data members of its class
that are of class type (or array thereof),
each such class has a trivial destructor.
</li>
</ul>
</blockquote>


<h3>12.6.2 Initializing bases and members [class.base.init]</h3>

<p>
Edit paragraph 4 as follows,
This edit arises from issue 509.
</p>

<blockquote>
<p>
If a given non-static data member or base class
is not named by a <var>mem-initializer-id</var>
(including the case where there is no <var>mem-initializer-list</var>
because the constructor has no <var>ctor-initializer</var>),
then <ins>the entity is default-initialized (8.5 dcl.init),
unless the entity is a variant member (9.5 class.union),
in which case no initialization is performed.</ins>
</p>
<ul>

<li>
<del>If the entity is a non-static non-variant data member
of (possibly cv-qualified) class type (or array thereof)
or a base class, and the entity class is a non-trivial class,
the entity is default-initialized (8.5).
If the entity is a non-static data member of a const-qualified type,
the entity class shall have a user-provided default constructor.</del>
</li>

<li>
<del>Otherwise, the entity is not initialized.
If the entity is of const-qualified type or reference type,
or of a (possibly cv-qualified) trivial class type (or array thereof)
containing (directly or indirectly) a member of a const-qualified type,
the program is ill-formed.</del>
</li>
</ul>

<p>
After the call to a constructor for class <code>X</code> has completed,
if a member of <code>X</code>
is neither specified in the constructor's <var>mem-initializer</var>s,
nor <del>default-initialized, nor value-initialized</del>
<ins>initialized</ins>,
nor given a value during execution of the
<var>compound-statement</var> of the body of the constructor,
the member has indeterminate value.
</p>
</blockquote>


<h3>12.7 Construction and destruction [class.cdtor]</h3>

<p>
Edit paragraph 1 as follows.
</p>

<blockquote>
<p>
<del>For an object of non-trivial class type (clause 9),
before the constructor begins execution
and after the destructor finishes execution,
referring to any non-static member or base class of the object
results in undefined behavior.</del>
<ins>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.
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>
</p>
</blockquote>

</body>
</html>
