<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=us-ascii">
<TITLE>
    Core "ready" Issues
   </TITLE>
</HEAD>
<BODY>
<TABLE ALIGN="RIGHT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT">
      Document number:
     </TD>
<TD>
       &#160;P2462R0</TD>
</TR>
<TR>
<TD ALIGN="RIGHT">
      Date:
     </TD>
<TD>
      &#160;2021-09-27</TD>
</TR>
<TR>
<TD ALIGN="RIGHT">
      Project:
     </TD>
<TD>
      &#160;Programming Language C++
     </TD>
</TR>
<TR>
<TD ALIGN="RIGHT">
      Reference:
     </TD>
<TD>
      &#160;ISO/IEC IS 14882:2020
     </TD>
</TR>
<TR>
<TD ALIGN="RIGHT">
      Reply to:
     </TD>
<TD>
      &#160;William M. Miller
     </TD>
</TR>
<TR>
<TD></TD>
<TD>
      &#160;Edison Design Group, Inc.
     </TD>
</TR>
<TR>
<TD></TD>
<TD>
      &#160;<A HREF="mailto://wmm@edg.com">wmm@edg.com</A></TD>
</TR>
</TABLE><BR CLEAR="ALL"><BR><CENTER>
<H2>
     Core Language Working Group "ready" Issues
     for the
     October, 2021 meeting
    </H2>
</CENTER><BR><P>
    References in this document reflect the section and paragraph
    numbering of document
    <A HREF="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/n4885.pdf">WG21 N4885</A>.
   </P>
<HR><A NAME="1249"></A><H4>1249.
  
Cv-qualification of nested lambda capture
</H4><B>Section: </B>7.5.5&#160; [expr.prim.lambda]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>James Widman
 &#160;&#160;&#160;

 <B>Date: </B>2011-03-02


<P>Consider the following example:</P>

<PRE>
    void f(int i) {
      auto l1 = [i] {
        auto l2 = [&amp;i] {
          ++i;    // Well-formed?
        };
      };
    }
</PRE>

<P>Because the <TT>l1</TT> lambda is not marked as <TT>mutable</TT>,
its <TT>operator()</TT> is <TT>const</TT>; however, it is not clear from
the wording of 7.5.5 [expr.prim.lambda] paragraph 16 whether the
captured member of the enclosing lambda is considered <TT>const</TT> or
not.</P>

<P><B>Proposed resolution (August, 2021):</B></P>

<P>Change 7.5.5.3 [expr.prim.lambda.capture] paragraph 14 as follows:</P>

<BLOCKQUOTE>

<P>If a <I>lambda-expression</I> <TT>m2</TT> captures an
entity and that entity is captured by an immediately
enclosing <I>lambda-expression</I> <TT>m1</TT>,
then <TT>m2</TT>'s capture is transformed as follows:</P>

<UL><LI><P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">if</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">If</SPAN> <TT>m1</TT> captures
the entity by copy, <TT>m2</TT> captures the corresponding
non-static data member of <TT>m1</TT>'s closure
type; <SPAN style="font-weight:bold;background-color:#A0FFA0">if <TT>m1</TT> is not <TT>mutable</TT>, the
non-static data member is considered to be
const-qualified.</SPAN></P></LI>

<LI><P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">if</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">If</SPAN> <TT>m1</TT> captures the
entity by reference, <TT>m2</TT> captures the same entity
captured by <TT>m1</TT>.</P></LI>

</UL>

</BLOCKQUOTE>

<BR><BR><HR><A NAME="1724"></A><H4>1724.
  
Unclear rules for deduction failure
</H4><B>Section: </B>13.10.3&#160; [temp.deduct]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>James Widman
 &#160;&#160;&#160;

 <B>Date: </B>2013-07-31




<P>According to 13.10.3 [temp.deduct] paragraph 8,</P>

<BLOCKQUOTE>

If a substitution results in an invalid type or expression, type deduction
fails. An invalid type or expression is one that would be ill-formed, with
a diagnostic required, if written using the substituted arguments.

</BLOCKQUOTE>

<P>Presumably the phrase &#8220;if written&#8221; refers to rewriting the
template declaration <I>in situ</I> with the substituted arguments, rather
than writing that type or expression at some arbitrary location, e.g.,</P>

<PRE>
  void g(double) = delete;

  template&lt;class T&gt; auto f(T t) -&gt; decltype(g(t));

  void g(int);

  void h() {
    typedef int T;
    T t = 42;
    g(t);  //<SPAN style="font-family:Times;font-style:italic"> Ok (I &#8220;wrote the substituted arguments&#8221;, and it seems fine)</SPAN>
    f(42); //<SPAN style="font-family:Times;font-style:italic"> Presumably substitution is meant to fail.</SPAN>
  }
</PRE>

<P>Perhaps a clearer formulation could be used?</P>

<P><B>Proposed resolution (August, 2021):</B></P>

<P>Change 13.10.3.1 [temp.deduct.general] paragraph 8 as follows:</P>

<BLOCKQUOTE>

If a substitution results in an invalid type or expression,
type deduction fails. An invalid type or expression is one
that would be ill-formed, with a diagnostic required, if
written <SPAN style="font-weight:bold;background-color:#A0FFA0">in the same context</SPAN> using the substituted
arguments.

</BLOCKQUOTE>

<BR><BR><HR><A NAME="1726"></A><H4>1726.
  
Declarator operators and conversion function
</H4><B>Section: </B>11.4.8.3&#160; [class.conv.fct]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>James Widman
 &#160;&#160;&#160;

 <B>Date: </B>2013-08-02




<P>Presumably the following example is intended to be ill-formed:</P>

<PRE>
  struct A {
    (*operator int*());
  };
  A a;
  int *x = a; //<SPAN style="font-family:Times;font-style:italic"> Ok?</SPAN>
</PRE>

<P>It is not clear, however, which rule is supposed to reject such a
<I>member-declaration</I>.</P>

<P><B>Proposed resolution (September, 2021):</B></P>

<P>Change 11.4.8.3 [class.conv.fct] paragraph 1 as follows,
splitting the paragraph into three paragraphs:</P>

<BLOCKQUOTE>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">A member function of a class <TT>X</TT> with a name of
the form</SPAN></P>

<UL><I>conversion-function-id:</I>
<UL><TT>operator</TT> <I>conversion-type-id</I>
</UL>
</UL>

<UL><I>conversion-type-id:</I>
<UL><I>type-specifier-seq conversion-declarator<SUB>opt</SUB></I>
</UL>
</UL>

<UL><I>conversion-declarator:</I>
<UL><I>ptr-operator conversion-declarator<SUB>opt</SUB></I>
</UL>
</UL>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">shall have no parameters and</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">A
declaration whose <I>declarator-id</I> is a
<I>conversion-function-id</I> shall declare a function or
function template, or an explicit instantiation or
specialization of a function template, that has no
parameters and is a non-static member of a class or class
template <TT>X</TT>; it</SPAN> specifies a conversion
from <TT>X</TT> to the type specified by
the <I>conversion-type-id</I>, interpreted as
a <I>type-id</I> (9.3.2 [dcl.name]). Such
functions are called <I>conversion functions</I>.</P>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">A <I>decl-specifier</I> in the <I>decl-specifier-seq</I>
of a conversion function (if any) shall be neither
a <I>defining-type-specifier</I> nor
<TT>static</TT>.</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">In a conversion function
declaration, each <I>decl-speciifer</I> in the optional
<I>decl-specifier-seq</I> shall be <TT>inline</TT>,
<TT>constexpr</TT>, <TT>consteval</TT>, <TT>virtual</TT>, or
an <I>explicit-specifier</I>.</SPAN> The type of the
conversion
function <SPAN style="text-decoration:line-through;background-color:#FFA0A0">(9.3.4.6 [dcl.fct])</SPAN> is
&#8220;<SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>noexcept</TT><I><SUB>opt</SUB></I></SPAN>
function taking no parameter <SPAN style="font-weight:bold;background-color:#A0FFA0"><I>cv-qualifier-seq<SUB>opt</SUB>
ref-qualifier<SUB>opt</SUB></I></SPAN>
returning <I>conversion-type-id</I>&#8221;.</P>

<P>A conversion function is never used to convert a
(possibly cv-qualified) object to the (possibly
cv-qualified) same object type (or a reference to it), to a
(possibly cv-qualified) base class of that type (or a
reference to it), or
to <I>cv</I> <TT>void</TT>.<SUP>102</SUP> [<I>Example
1:</I>...</P>

</BLOCKQUOTE>

<BR><BR><HR><A NAME="1733"></A><H4>1733.
  
Return type and value for <TT>operator=</TT> with <I>ref-qualifier</I>
</H4><B>Section: </B>9.5.2&#160; [dcl.fct.def.default]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>James Widman
 &#160;&#160;&#160;

 <B>Date: </B>2013-08-09




<P>9.5.2 [dcl.fct.def.default] paragraph 1 specifies that an
explicitly-defaulted function shall</P>

<BLOCKQUOTE>

have the same declared function type (except for possibly
differing <I>ref-qualifier</I>s and except that in the case of a copy
constructor or copy assignment operator, the parameter type may be
&#8220;reference to non-const <TT>T</TT>&#8221;, where <TT>T</TT> is the
name of the member function's class) as if it had been implicitly
declared...

</BLOCKQUOTE>

<P>This allows an example like</P>

<PRE>
  struct A {
    A&amp; operator=(A const&amp;) &amp;&amp; = default; 
  };
</PRE>

<P>but forbids</P>

<PRE>
  struct B {
    B&amp;&amp; operator=(B const&amp;) &amp;&amp; = default; 
  };
</PRE>

<P>which seems backward.</P>

<P>In addition, _N4750_.15.8 [class.copy] paragraph 22 only specifies the
return value for implicitly-declared copy/move assignment operators,
not for explicitly-defaulted ones.</P>

<P><B>Proposed resolution (August, 2021):</B></P>

<OL><LI><P>Change 11.4.6 [class.copy.assign] paragraph 6 as follows:</P></LI>

<BLOCKQUOTE>

The implicitly-declared copy/move assignment operator for
class <TT>X</TT> has the return type <TT>X&amp;</TT><SPAN style="text-decoration:line-through;background-color:#FFA0A0">;
it returns the object for which the assignment operator is
invoked, that is, the object assigned to</SPAN>. An
implicitly-declared copy/move assignment operator is an
inline public member of its class.

</BLOCKQUOTE>

<LI><P>Add the following as a new paragraph following
11.4.6 [class.copy.assign] paragraph 13:</P></LI>

<BLOCKQUOTE>

<P>The implicitly-defined copy assignment operator for a union
<TT>X</TT> copies the object representation
(6.8 [basic.types]) of <TT>X</TT>. If the source and
destination of the assignment are not the same object, then
for each object nested within (6.7.2 [intro.object])
the object that is the source of the copy, a corresponding
object <I>o</I> nested within the destination is created,
and the lifetime of <I>o</I> begins before the copy is
performed.</P>

<P><SPAN style="font-weight:bold;background-color:#A0FFA0">The implicitly-defined copy/move assignment operator
for a class returns the object for which the assignment
operator is invoked, that is, the object assigned
to.</SPAN></P>

</BLOCKQUOTE>

</OL>

<P><I>[Note: The first point in the issue, that of the
relationship between the ref-qualifier and the return type,
will be referred to EWG for consideration. The draft
resolution above addresses only the second point of the
issue.</I></P>

<BR><BR><HR><A NAME="2484"></A><H4>2484.
  
<TT>char8_t</TT> and <TT>char16_t</TT> in integral promotions
</H4><B>Section: </B>7.3.7&#160; [conv.prom]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>Richard Smith
 &#160;&#160;&#160;

 <B>Date: </B>2021-04-01


<P>According to 7.3.7 [conv.prom] paragraphs 1-2,</P>

<BLOCKQUOTE>

<P>A prvalue of an integer type other than <TT>bool</TT>,
<TT>char16_t</TT>, <TT>char32_t</TT>, or <TT>wchar_t</TT>
whose integer conversion rank (6.8.5 [conv.rank])
is less than the rank of <TT>int</TT> can be converted to a
prvalue of type <TT>int</TT> if <TT>int</TT> can represent
all the values of the source type; otherwise, the source
prvalue can be converted to a prvalue of type <TT>unsigned
int</TT>.</P>

<P>A prvalue of type <TT>char16_t</TT>, <TT>char32_t</TT>,
or <TT>wchar_t</TT> (6.8.2 [basic.fundamental]) can be
converted to a prvalue of the first of the following types
that can represent all the values of its underlying type:
<TT>int</TT>, <TT>unsigned int</TT>, <TT>long int</TT>,
<TT>unsigned long int</TT>, <TT>long long int</TT>, or
<TT>unsigned long long int</TT>. If none of the types in that
list can represent all the values of its underlying type, a
prvalue of type <TT>char16_t</TT>, <TT>char32_t</TT>, or
<TT>wchar_t</TT> can be converted to a prvalue of its
underlying type.</P>

</BLOCKQUOTE>

<P>Because of its omission from the list of excluded types
(perhaps as an oversight when it was
added), <TT>char8_t</TT> is handled in the first
paragraph. However, <TT>char16_t</TT> falls into the second
paragraph, even though it is guaranteed to be convertible
to <TT>int</TT> or <TT>unsigned int</TT>. This seems
inconsistent, so perhaps <TT>char8_t</TT> should be moved to
the second paragraph or <TT>char16_t</TT> moved to the first?</P>

<P><B>Notes from the August, 2021 teleconference:</B></P>

<P><TT>char8_t</TT> should be handled by the second
paragraph by including it in all three lists of types in the
two paragraphs.</P>

<P><B>Proposed resolution (August, 2021):</B></P>

<P>Change 7.3.7 [conv.prom] paragraphs 1 and 2 as follows:</P>

<BLOCKQUOTE>

<P>A prvalue of an integer type other
than <TT>bool</TT>, <SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>char8_t</TT>,</SPAN>
<TT>char16_t</TT>, <TT>char32_t</TT>, or <TT>wchar_t</TT>
whose integer conversion rank (6.8.5 [conv.rank])
is less than the rank of <TT>int</TT> can be converted to a
prvalue of type <TT>int</TT> if <TT>int</TT> can represent
all the values of the source type; otherwise, the source
prvalue can be converted to a prvalue of type <TT>unsigned
int</TT>.</P>

<P>A prvalue of type <SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>char8_t</TT>,</SPAN>
<TT>char16_t</TT>, <TT>char32_t</TT>,
or <TT>wchar_t</TT> (6.8.2 [basic.fundamental]) can be
converted to a prvalue of the first of the following types
that can represent all the values of its underlying type:
<TT>int</TT>, <TT>unsigned int</TT>, <Tt>long int</Tt>,
<TT>unsigned long int</TT>, <TT>long long int</TT>, or
<TT>unsigned long long int</TT>. If none of the types in
that list can represent all the values of its underlying
type, a prvalue of type <SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>char8_t</TT>,</SPAN>
<TT>char16_t</TT>, <TT>char32_t</TT>,
or <TT>wchar_t</TT> can be converted to a prvalue of its
underlying type.</P>

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2486"></A><H4>2486.
  
Call to <TT>noexcept</TT> function via <TT>noexcept(false)</TT> pointer/lvalue
</H4><B>Section: </B>7.6.1.3&#160; [expr.call]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>Jiang An
 &#160;&#160;&#160;

 <B>Date: </B>2021-03-27


<P>According to 7.6.1.3 [expr.call] paragraph 6,</P>

<BLOCKQUOTE>

Calling a function through an expression whose function type
is different from the function type of the called function's
definition results in undefined behavior.

</BLOCKQUOTE>

<P>This restriction should exempt calling a <TT>noexcept</TT>
function where the function type of the expression is
identical except that it is <TT>noexcept(false)</TT>.</P>

<P>In addition, 7.6.1.9 [expr.static.cast] paragraph 7
currently forbids <TT>static_cast</TT> from converting a
function pointer or member function pointer from
<TT>noexcept(false)</TT> to <TT>noexcept</TT>:</P>

<BLOCKQUOTE>

The inverse of any standard conversion sequence
(7.3 [conv]) not containing an
lvalue-to-rvalue (7.3.2 [conv.lval]),
array-to-pointer (7.3.3 [conv.array]),
function-to-pointer (7.3.4 [conv.func]), null
pointer (7.3.12 [conv.ptr]), null member pointer
(7.3.13 [conv.mem]), boolean
(7.3.15 [conv.bool]), or function pointer
(7.3.14 [conv.fctptr]) conversion, can be performed
explicitly using static_cast.

</BLOCKQUOTE>

<P>This restriction should also be relaxed, allowing
binding a constexpr reference to the result of the
reversed conversion.</P>



<P><B>Notes from the August, 2021 teleconference:</B></P>

<P>CWG agreed that it should be permitted to call a
<TT>noexcept</TT> function via an expression that is
<TT>noexcept(false)</TT>; since the implicit conversion
is allowed, the failure to allow the call is clearly
just an oversight. The question of whether to allow the
<TT>static_cast</TT> in the inverse direction, as well as
whether to allow calling a <TT>noexcept(false)</TT> function
via a <TT>noexcept</TT> expression (which would result in
undefined behavior only if the function actually threw an
exception) was deemed to be a matter for EWG and was thus
split off into issue 2500.
</P>

<P><B>Proposed resolution (September, 2021):</B></P>

<P>Change 7.6.1.3 [expr.call] paragraph 6 as follows:</P>

<BLOCKQUOTE>

Calling a function through an expression whose function type
<SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>E</TT></SPAN> is different from the function
type <SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>F</TT></SPAN> of the called function's
definition results in undefined behavior <SPAN style="font-weight:bold;background-color:#A0FFA0">unless the
type &#8220;pointer to <TT>F</TT>&#8221; can be converted to
the type &#8220;pointer to <TT>E</TT>&#8221; via a function
pointer conversion
(7.3.14 [conv.fctptr])</SPAN>. <SPAN style="font-weight:bold;background-color:#A0FFA0">[<I>Note:</I> The
exception applies when the expression has the type of a
potentially-throwing function, but the called function has a
non-throwing exception specification, and the function types
are otherwise the same. &#8212;<I>end note</I>]</SPAN>

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2490"></A><H4>2490.
  
Restrictions on destruction in constant expressions
</H4><B>Section: </B>7.7&#160; [expr.const]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>Jiang An
 &#160;&#160;&#160;

 <B>Date: </B>2021-05-04


<P>According to 7.7 [expr.const] paragraph 6,</P>

<BLOCKQUOTE>

<P>For the purposes of determining whether an
expression <I>E</I> is a core constant expression, the
evaluation of a call to a member function of
<TT>std::allocator&lt;T&gt;</TT> as defined in
20.10.10.2 [allocator.members], where <TT>T</TT> is a
literal type, does not disqualify <I>E</I> from being a core
constant expression, even if the actual evaluation of such a
call would otherwise fail the requirements for a core
constant expression. Similarly, the evaluation of a call to
<TT>std::destroy_at</TT>, <TT>std::ranges::destroy_at</TT>,
<TT>std::construct_at</TT>,
or <TT>std::ranges::construct_at</TT> does not
disqualify <TT>E</TT> from being a core constant expression
unless:</P>

<UL><LI><P>for a call to <TT>std::construct_at</TT> or
<TT>std::ranges::construct_at</TT>, the first argument, of
type <TT>T*</TT>, does not point to storage allocated with
<TT>std::allocator&lt;T&gt;</TT> or to an object whose
lifetime began within the evaluation of <I>E</I>, or the
evaluation of the underlying constructor call
disqualifies <I>E</I> from being a core constant expression,
or</P></LI>

<LI><P>for a call to <TT>std::destroy_at</TT> or
<TT>std::ranges::destroy_at</TT>, the first argument, of
type <TT>T*</TT>, does not point to storage allocated with
<TT>std::allocator&lt;T&gt;</TT> or to an object whose
lifetime began within the evaluation of <I>E</I>, or the
evaluation of the underlying destructor call
disqualifies <I>E</I> from being a core constant
expression.</P></LI>

</UL>

</BLOCKQUOTE>

<P>There are, however, no specific restrictions in
7.7 [expr.const] regarding destructor or
pseudo-destructor calls. In particular, a constexpr
destructor can be called for any object, regardless of
how it was constructed or the start of its lifetime,
and similarly for pseudo-destructor calls. This seems
inconsistent.</P>

<P>If those restrictions are added, would the specific
restrictions on library destruction facilities still be
needed?</P>

<P><B>Notes from the August, 2021 teleconference:</B></P>

<P>CWG agreed that since trivial destructors and
pseudo-destructors are now considered to end the lifetime of
the object for which they are called, they should be
prohibited from being invoked for a runtime object in a
constant expression.</P>

<P><B>Proposed resolution (August, 2021):</B></P>

<OL><LI><P>Change 7.7 [expr.const] paragraph 5 as follows:</P></LI>

<BLOCKQUOTE>

<P>An expression <I>E</I> is a <I>core constant expression</I>
unless the evaluation of <I>E</I>, following the rules of the
abstract machine (6.9.1 [intro.execution]), would
evaluate one of the following:</P>

<UL><LI><P>...</P></LI>

<LI><P>a modification of an object
(7.6.19 [expr.ass], 7.6.1.6 [expr.post.incr],
7.6.2.3 [expr.pre.incr]) unless it is applied to a
non-volatile lvalue of literal type that refers to a
non-volatile object whose lifetime began within the
evaluation of <I>E</I>;</P></LI>

<LI><P><SPAN style="font-weight:bold;background-color:#A0FFA0">an invocation of a destructor
(11.4.7 [class.dtor]) or a function call whose
<I>postfix-expression</I> names a pseudo-destructor
(7.6.1.3 [expr.call]), in either case for an
object whose lifetime did not begin within the evaluation
of <I>E</I>;</SPAN></P></LI>

<LI><P>a <I>new-expression</I> (7.6.2.8 [expr.new]),
unless...</P></LI>

</UL>

</BLOCKQUOTE>

<LI><P>Change 7.7 [expr.const] paragraph 6 as follows,
merging the single remaining bulleted item into the running text
of the paragraph:</P></LI>

<BLOCKQUOTE>

<P>For the purposes of determining whether an
expression <I>E</I> is a core constant expression, the
evaluation of a call to a member function of
<TT>std::allocator&lt;T&gt;</TT> as defined in
20.10.10.2 [allocator.members], where <TT>T</TT> is a
literal type, does not disqualify <I>E</I> from being a core
constant expression, even if the actual evaluation of such a
call would otherwise fail the requirements for a core
constant expression. Similarly, the evaluation of a call to
<SPAN style="text-decoration:line-through;background-color:#FFA0A0"><TT>std::destroy_at</TT>, <TT>std::ranges::destroy_at</TT>,</SPAN>
<TT>std::construct_at</TT><SPAN style="text-decoration:line-through;background-color:#FFA0A0">,</SPAN>
or <TT>std::ranges::construct_at</TT> does not
disqualify <I>E</I> from being a core constant expression
unless<SPAN style="text-decoration:line-through;background-color:#FFA0A0">:</SPAN></P>

<UL><LI><P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">for a call to <TT>std::construct_at</TT> or
<TT>std::ranges::construct_at</TT>,</SPAN> the first
argument, of type <TT>T*</TT>, does not point to storage
allocated with
<TT>std::allocator&lt;T&gt;</TT> or to an object whose
lifetime began within the evaluation of <I>E</I>, or the
evaluation of the underlying constructor call
disqualifies <I>E</I> from being a core constant
expression<SPAN style="text-decoration:line-through;background-color:#FFA0A0">, or</SPAN></P></LI>

<LI><P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">for a call to <TT>std::destroy_at</TT> or
<TT>std::ranges::destroy_at</TT>, the first argument, of
type <TT>T*</TT>, does not point to storage allocated with
<TT>std::allocator&lt;T&gt;</TT> or to an object whose
lifetime began within the evaluation of <I>E</I>, or the
evaluation of the underlying destructor call
disqualifies <I>E</I> from being a core constant
expression</SPAN>.</P></LI>

</UL>

</BLOCKQUOTE>

</OL>

<BR><BR><HR><A NAME="2491"></A><H4>2491.
  
Export of typedef after its first declaration
</H4><B>Section: </B>10.2&#160; [module.interface]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>Richard Smith
 &#160;&#160;&#160;

 <B>Date: </B>2021-04-16


<P>According to 10.2 [module.interface] paragraph 6,</P>

<BLOCKQUOTE>

<P>A redeclaration of an entity
or <I>typedef-name</I> <TT>X</TT> is implicitly exported if
<TT>X</TT> was introduced by an exported declaration;
otherwise it shall not be exported.  [<I>Example 4:</I></P>

<PRE>
  export module M;
  struct S { int n; };
  typedef S S;
  export typedef S S; //<SPAN style="font-family:Times;font-style:italic"> OK, does not redeclare an entity</SPAN>
  export struct S;    //<SPAN style="font-family:Times;font-style:italic"> error: exported declaration follows non-exported declaration</SPAN>
</PRE>

<P>&#8212;<I>end example</I>]</P>

</BLOCKQUOTE>

<P>The normative text says that exporting a typedef that was
not exported on its first declaration is ill-formed, but the
example does so and states that it is &#8220;OK&#8221;. This is a
contradiction that was introduced by the changes in paper
P1787R6; the previous normative text supported the usage in
the example.</P>

<P>(See also <A HREF="https://github.com/cplusplus/draft/issues/4540">
editorial issue 4540</A>.)</P>

<P><B>Proposed resolution, August, 2021:</B></P>

<P>Change 10.2 [module.interface] paragraph 6 as follows:</P>

<BLOCKQUOTE>

A redeclaration of an entity <SPAN style="text-decoration:line-through;background-color:#FFA0A0">or <I>typedef-name</I></SPAN>
<TT>X</TT> is implicitly exported if <TT>X</TT> was
introduced by an exported declaration; otherwise it shall
not be exported.

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2496"></A><H4>2496.
  
<I>ref-qualifier</I>s and virtual overriding
</H4><B>Section: </B>11.7.3&#160; [class.virtual]
 &#160;&#160;&#160;

 <B>Status: </B>ready
 &#160;&#160;&#160;

 <B>Submitter: </B>Jens Maurer
 &#160;&#160;&#160;

 <B>Date: </B>2021-06-16




<P>According to 11.7.3 [class.virtual] paragraph 2,</P>

<BLOCKQUOTE>

If a virtual member function <I>F</I> is declared in a class
<I>B</I>, and, in a class <I>D</I> derived (directly or
indirectly) from <I>B</I>, a declaration of a member
function <I>G</I> corresponds (6.4.1 [basic.scope.scope])
to a declaration of <I>F</I>, ignoring
trailing <I>requires-clause</I>s, then <I>G</I>
overrides<SUP>105</SUP> <I>F</I>.

</BLOCKQUOTE>

<P>This is different from C++20, where <I>G</I> was
considered to hide, rather than to override, <I>F</I> if
the <I>ref-qualifier</I>s of the declarations are
different. This unintentional change could be addressed
in one of two ways. To restore the C++20 behavior, the
cited paragraph could be amended to:</P>

<BLOCKQUOTE>

...a declaration of a member
function <I>G</I> corresponds (6.4.1 [basic.scope.scope])
to a declaration of <I>F</I>, ignoring
trailing <I>requires-clause</I>s, <SPAN style="font-weight:bold;background-color:#A0FFA0">and has the same
<I>ref-qualifier</I> (if any),</SPAN> then <I>G</I>
overrides<SUP>105</SUP> <I>F</I>.

</BLOCKQUOTE>

<P>Alternatively, such a situation could be regarded as an
ill-formed attempt to override the base class function,
which could be specified by adding the following as a new
paragraph preceding 11.7.3 [class.virtual] paragraph
7:</P>

<BLOCKQUOTE>

<P><SPAN style="font-weight:bold;background-color:#A0FFA0">The <I>ref-qualifier</I>, or lack thereof, of an
overriding function shall be the same as that of the
overridden function.</SPAN></P>

<P>The return type of an overriding function shall be either
identical to the return type of the overridden function or
<I>covariant</I>...</P>

</BLOCKQUOTE>

<P><B>Notes from the August, 2021 teleconference:</B></P>

<P>CWG preferred the second option.</P>

<P><B>Proposed resolution, August, 2021:</B></P>

<P>Add the following as a new paragraph preceding
11.7.3 [class.virtual] paragraph 7:</P>

<BLOCKQUOTE>

<P><SPAN style="font-weight:bold;background-color:#A0FFA0">The <I>ref-qualifier</I>, or lack thereof, of an
overriding function shall be the same as that of the
overridden function.</SPAN></P>

<P>The return type of an overriding function shall be either
identical to the return type of the overridden function or
<I>covariant</I>...</P>

</BLOCKQUOTE>

<BR><BR></BODY>
</HTML>
