<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=us-ascii">
<TITLE>
    Core "tentatively ready" Issues
   </TITLE>
</HEAD>
<BODY>
<TABLE ALIGN="RIGHT" CELLSPACING="0" CELLPADDING="0">
<TR>
<TD ALIGN="RIGHT">
      Document number:
     </TD>
<TD>
       &#160;P2238R0</TD>
</TR>
<TR>
<TD ALIGN="RIGHT">
      Date:
     </TD>
<TD>
      &#160;2020-10-26</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:2017
     </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 "tentatively ready" Issues
     for the
     November, 2020 virtual 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/2020/n4868.pdf">WG21 N4868</A>.
   </P>
<HR><A NAME="2312"></A><H4>2312.
  
Structured bindings and <TT>mutable</TT>
</H4><B>Section: </B>9.6&#160; [dcl.struct.bind]
 &#160;&#160;&#160;

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

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

 <B>Date: </B>2016-08-11




<P>An example like the following is currently ill-formed:</P>

<PRE>
  struct A { mutable int n; }; 
  void f() { 
    const auto [a] = A(); 
    a = 0; 
  } 
</PRE>

<P>According to 9.6 [dcl.struct.bind] paragraph 4, the type of
<TT>a</TT> is <TT>const int</TT>, since the implicitly-declared variable
is <TT>const</TT>. This seems obviously wrong: the member <TT>n</TT> is
mutable, so the member access expression <TT>e.n</TT> has
type <TT>int</TT>, which should also be the type
of <TT>a</TT>. (<TT>mutable</TT> should presumably be taken into account
when forming the referenced type too, so that <TT>decltype(a)</TT>
is <TT>int</TT> as would presumably be expected, rather than <TT>const
int</TT>.)</P>

<P><B>Proposed resolution, March, 2018: [SUPERSEDED]</B></P>

<P>Change 9.6 [dcl.struct.bind] paragraph 4 as follows:</P>

<BLOCKQUOTE>

...Designating the non-static data members of <TT>E</TT>
as <TT>m<SUB>0</SUB></TT>, <TT>m<SUB>1</SUB></TT>, <TT>m<SUB>2</SUB></TT>,
... (in declaration order), each <TT>v</TT><I><SUB>i</SUB></I> is the name
of an lvalue that refers to <SPAN style="text-decoration:line-through;background-color:#FFA0A0">the member <TT>m</TT><I><SUB>i</SUB></I>
of <TT>e</TT> and whose type is <I>cv</I> <TT>T</TT><I><SUB>i</SUB></I>,
where <TT>T</TT><I><SUB>i</SUB></I> is the declared type of that
member</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0"><TT>e.m</TT><I><SUB>i</SUB></I></SPAN>; the referenced
type is <SPAN style="text-decoration:line-through;background-color:#FFA0A0"><I>cv</I> <TT>T</TT><I><SUB>i</SUB></I></SPAN>
<SPAN style="font-weight:bold;background-color:#A0FFA0">the type of <TT>e.m</TT><I><SUB>i</SUB></I></SPAN>. The lvalue is a
bit-field if...

</BLOCKQUOTE>

<P><B>Notes from the June, 2018 meeting:</B></P>

<P>It was observed that this resolution does not handle members with
reference type correctly. The main problem seems to be the statement
in 7.6.1.5 [expr.ref] paragraph 4, which directly handles
members with reference type rather than allowing the type of the
member to be the result type and relying on the general rule that
turns reference-typed expressions into lvalues.</P>

<P><B>Proposed resolution (April, 2020):</B></P>

<P>Change 9.6 [dcl.struct.bind] paragraph 5 as follows:</P>

<BLOCKQUOTE>

<P>...Designating the non-static data members of <TT>E</TT>
as <TT>m<SUB>0</SUB></TT>, <TT>m<SUB>1</SUB></TT>,
<TT>m<SUB>2</SUB></TT>, ... (in declaration order),
each <TT>v</TT><SUB><I>i</I></SUB> is the name of an lvalue
that refers to the member <TT>m</TT><SUB><I>i</I></SUB>
of <I>e</I> and whose type
is <SPAN style="text-decoration:line-through;background-color:#FFA0A0"><I>cv</I> <TT>T</TT><SUB><I>i</I></SUB>,
where <TT>T</TT><SUB><I>i</I></SUB> is the declared type of
that member</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">that of <I>e</I><TT>.m</TT><SUB><I>i</I></SUB>
(7.6.1.5 [expr.ref])</SPAN>; the referenced type
is <SPAN style="text-decoration:line-through;background-color:#FFA0A0"><I>cv</I> <TT>T</TT><SUB><I>i</I></SUB></SPAN>
<SPAN style="font-weight:bold;background-color:#A0FFA0">the declared type of <TT>m</TT><SUB><I>i</I></SUB> if
that type is a reference type, or the type of
<I>e</I><TT>.m</TT><SUB><I>i</I></SUB> otherwise</SPAN>.  The
lvalue is a bit-field if that member is a bit-field.</P>

<P>[<I>Example 2:</I></P>

<PRE>
  struct S { <SPAN style="font-weight:bold;background-color:#A0FFA0">mutable</SPAN> int x1 : 2; volatile double y1; };
  S f();
  const auto [ x, y ] = f();
</PRE>

<P>The type of the <I>id-expression</I> <TT>x</TT> is
&#8220;<TT><SPAN style="text-decoration:line-through;background-color:#FFA0A0">const</SPAN> int</TT>&#8221;, the type of
the <I>id-expression</I> <TT>y</TT> is &#8220;<TT>const
volatile double</TT>&#8221;. &#8212;<I>end example</I>]</P>

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2369"></A><H4>2369.
  
Ordering between constraints and substitution
</H4><B>Section: </B>13.10.3&#160; [temp.deduct]
 &#160;&#160;&#160;

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

 <B>Submitter: </B>Agustin Berg&#233;
 &#160;&#160;&#160;

 <B>Date: </B>2017-10-09


<P>The specification of template argument deduction in
13.10.3 [temp.deduct] paragraph 5 specifies the order of
processing as:</P>

<OL><LI><P>substitute explicitly-specified template arguments
throughout the template parameter list and type;</P></LI>

<LI><P>deduce template arguments from the resulting function
signature;</P></LI>

<LI><P>check that non-dependent parameters can be initialized from
their arguments;</P></LI>

<LI><P>substitute deduced template arguments into the template
parameter list and particularly into any needed default arguments
to form a complete template argument list;;</P></LI>

<LI><P>substitute resulting template arguments throughout the
type;</P></LI>

<LI><P>check that the associated constraints are satisfied;</P></LI>

<LI><P>check that remaining parameters can be initialized from
their arguments.</P></LI>

</OL>

<P>This ordering yields unexpected differences between concept and
SFINAE implementations. For example:</P>

<PRE>
   template &lt;typename T&gt;
   struct static_assert_integral {
     static_assert(std::is_integral_v&lt;T&gt;);
     using type = T;
   };

   struct fun {
     template &lt;typename T,
       typename Requires = std::enable_if_t&lt;std::is_integral_v&lt;T&gt;&gt;&gt;
       typename static_assert_integral&lt;T&gt;::type
     operator()(T) {}
   };
</PRE>

<P>Here the substitution ordering guarantees are leveraged to prevent
<TT>static_assert_integral&lt;T&gt;</TT> from being instantiated
when the constraints are not satisfied. As a result, the following
assertion holds:</P>

<PRE>
   static_assert(!std::is_invocable_v&lt;fun, float&gt;);
</PRE>

<P>A version of this code written using constraints
unexpectedly behaves differently:</P>

<PRE>
   struct fun {
     template &lt;typename T&gt;
       requires std::is_integral_v&lt;T&gt;
     typename static_assert_integral&lt;T&gt;::type
     operator()(T) {}
   };
</PRE>

<P>or</P>

<PRE>
   struct fun {
     template &lt;typename T&gt;
     typename static_assert_integral&lt;T&gt;::type
     operator()(T) requires std::is_integral_v&lt;T&gt; {}
   };

   static_assert(!std::is_invocable_v&lt;fun, float&gt;); //<SPAN style="font-family:Times;font-style:italic"> error: static assertion failed: </SPAN>std::is_integral_v&lt;T&gt; 
</PRE>

<P>Perhaps steps 5 and 6 should be interchanged.</P>



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

<OL><LI><P>Delete paragraph 10 of 13.10.3.2 [temp.deduct.call]:</P></LI>

<BLOCKQUOTE>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">If deduction succeeds for all parameters that
contain <I>template-parameter</I>s that participate in
template argument deduction, and all template arguments are
explicitly specified, deduced, or obtained from default
template arguments, remaining parameters are then compared
with the corresponding arguments. For each
remaining parameter P with a type that was non-dependent
before substitution of any explicitly-specified template
arguments, if the corresponding argument A cannot be
implicitly converted to P, deduction fails.  [<I>Note 2:</I>
Parameters with dependent types in which
no <I>template-parameter</I>s participate in template
argument deduction, and parameters that became non-dependent
due to substitution of explicitly-specified template
arguments, will be checked during overload
resolution. &#8212;<I>end note</I>]</SPAN></P>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">[<I>Example 9:</I></SPAN></P>

<PRE>
<SPAN style="text-decoration:line-through;background-color:#FFA0A0">  template &lt;class T&gt; struct Z {
    typedef typename T::x xx;
  };
  template &lt;class T&gt; typename Z&lt;T&gt;::xx f(void *, T); //<SPAN style="font-family:Times;font-style:italic"> #1</SPAN>
  template &lt;class T&gt; void f(int, T);                 //<SPAN style="font-family:Times;font-style:italic"> #2</SPAN>
  struct A {} a;
  int main() {
    f(1, a);   //<SPAN style="font-family:Times;font-style:italic"> OK, deduction fails for #1 because there is no conversion from </SPAN>int<SPAN style="font-family:Times;font-style:italic"> to </SPAN>void*
  }</SPAN>
</PRE>

<P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">&#8212;<I>end example</I>]</SPAN></P>

</BLOCKQUOTE>

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

<BLOCKQUOTE>

<P>...When all template arguments have been deduced or obtained
from default template arguments, all uses of template
parameters in the template parameter list of the template
<SPAN style="text-decoration:line-through;background-color:#FFA0A0">and the function type</SPAN> are replaced with the
corresponding deduced or default argument values. If the
substitution results in an invalid type, as described above,
type deduction fails. If the function template has
associated constraints (13.5.3 [temp.constr.decl]), those
constraints are checked for satisfaction
(13.5.2 [temp.constr.constr]). If the constraints are not
satisfied, type deduction fails. <SPAN style="font-weight:bold;background-color:#A0FFA0">In the context of a
function call, if type deduction has not yet failed, then
for those function parameters for which the function call
has arguments, each function parameter with a type that was
non-dependent before substitution of any explicitly-specified
template arguments is checked against its corresponding
argument; if the corresponding argument cannot be implicitly
converted to the parameter type, type deduction fails.
[<I>Note:</I> Overload resolution will check the other
parameters, including parameters with dependent types in
which no template parameters participate in template
argument deduction and parameters that became non-dependent
due to substitution of explicitly-specified template
arguments. &#8212;<I>end note</I>] If type deduction has not
yet failed, then all uses of template parameters in the
function type are replaced with the corresponding deduced or
default argument values. If the substitution results in an
invalid type, as described above, type deduction fails.
[<I>Example:</I></SPAN></P>

<PRE>
<SPAN style="font-weight:bold;background-color:#A0FFA0">  template &lt;class T&gt; struct Z {
    typedef typename T::x xx;
  };
  template &lt;class T&gt; concept C = requires { typename T::A; };
  template &lt;C T&gt; typename Z&lt;T&gt;::xx f(void *, T); //<SPAN style="font-family:Times;font-style:italic"> #1</SPAN>
  template &lt;class T&gt; void f(int, T);             //<SPAN style="font-family:Times;font-style:italic"> #2</SPAN>
  struct A {} a;
  struct ZZ {
    template &lt;class T, class = typename Z&lt;T&gt;::xx&gt; operator T *();
    operator int();
  };
  int main() {
    ZZ zz;
    f(1, a);   //<SPAN style="font-family:Times;font-style:italic"> OK, deduction fails for #1 because there is no conversion from </SPAN>int<SPAN style="font-family:Times;font-style:italic"> to </SPAN>void*
    f(zz, 42); //<SPAN style="font-family:Times;font-style:italic"> OK, deduction fails for #1 because </SPAN>C&lt;int&gt;<SPAN style="font-family:Times;font-style:italic"> is not satisfied</SPAN>
  }</SPAN>
</PRE>

<P><SPAN style="font-weight:bold;background-color:#A0FFA0">&#8212;<I>end example</I>]</SPAN></P>

</BLOCKQUOTE>

</OL>

<BR><BR><HR><A NAME="2452"></A><H4>2452.
  
Flowing off the end of a coroutine
</H4><B>Section: </B>8.7.5&#160; [stmt.return.coroutine]
 &#160;&#160;&#160;

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

 <B>Submitter: </B>Lewis Baker
 &#160;&#160;&#160;

 <B>Date: </B>2020-02-14


<P>There are two references to &#8220;flowing off the end of a
coroutine&#8221;, specifically in 8.7.5 [stmt.return.coroutine]
paragraph 3:</P>

<BLOCKQUOTE>

If <I>p</I><TT>.return_void()</TT> is a valid expression,
flowing off the end of a coroutine is equivalent to a
<TT>co_return</TT> with no operand; otherwise flowing off the
end of a coroutine results in undefined behavior.

</BLOCKQUOTE>

<P>and 9.5.4 [dcl.fct.def.coroutine] paragraph 11:</P>

<BLOCKQUOTE>

The coroutine state is destroyed when control flows off the
end of the coroutine or...

</BLOCKQUOTE>

<P>These mean different things and should be clarified.</P>

<P><B>Proposed resolution (July, 2020):</B></P>

<P>Change 8.7.5 [stmt.return.coroutine] paragraph 3 as follows:</P>

<BLOCKQUOTE>

If <I>p</I><TT>.return_void()</TT> is a valid expression,
flowing off the end of a
coroutine<SPAN style="font-weight:bold;background-color:#A0FFA0">'s <I>function-body</I></SPAN> is equivalent to
a <TT>co_return</TT> with no operand;otherwise flowing off
the end of a coroutine<SPAN style="font-weight:bold;background-color:#A0FFA0">'s <I>function-body</I></SPAN>
results in undefined behavior.

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2457"></A><H4>2457.
  
Unexpanded parameter packs don't make a function type dependent
</H4><B>Section: </B>13.8.3.2&#160; [temp.dep.type]
 &#160;&#160;&#160;

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

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

 <B>Date: </B>2020-07-28


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

<PRE>
  template&lt;typename ...T&gt; auto f() {
    using F = int(*)(int (...p)[sizeof(sizeof(T))]);
    //<SPAN style="font-family:Times;font-style:italic"> ...</SPAN>
  }

</PRE>

<P><TT>F</TT> is not covered in the list of cases in
13.8.3.2 [temp.dep.type] paragraph 9, because the types
from which the function type is constructed are not
dependent types. (The parameter pack <TT>p</TT> is of type
<TT>int[sizeof(size_t)]</TT>.) Similar situations arise with
non-injective alias templates.</P>

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

<P>Change 13.8.3.2 [temp.dep.type] paragraph 9 as
follows:</P>

<BLOCKQUOTE>

<P>A type is dependent if it is</P>

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

<LI><P> an array type whose element type is dependent or whose
bound (if any) is value-dependent,</P></LI>

<LI><P><SPAN style="font-weight:bold;background-color:#A0FFA0">a function type whose parameters include one or
more function parameter packs,</SPAN></P></LI>

<LI><P>a function type whose exception specification is
value-dependent,</P></LI>

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

</UL>

</BLOCKQUOTE>

<P>(We do have the relevant wording for pack expansions
in <I>simple-template-id</I>s in bullet 9.8, so that similar
case is already handled.)</P>

<BR><BR><HR><A NAME="2460"></A><H4>2460.
  
C language linkage and constrained non-template friends
</H4><B>Section: </B>9.11&#160; [dcl.link]
 &#160;&#160;&#160;

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

 <B>Submitter: </B>Hubert Tong
 &#160;&#160;&#160;

 <B>Date: </B>2020-03-23




<P>According to 13.7.5 [temp.friend] paragraph 9,</P>

<BLOCKQUOTE>

A non-template friend declaration with
a <I>requires-clause</I> shall be a definition. A friend
function template with a constraint that depends on a
template parameter from an enclosing template shall be a
definition.  Such a constrained friend function or function
template declaration does not declare the same function or
function template as a declaration in any other scope.

</BLOCKQUOTE>

<P>However, this specification conflicts with the treatment
of functions with C language linkage in 9.11 [dcl.link]
paragraph 7:</P>

<BLOCKQUOTE>

At most one function with a particular name can have C
language linkage. Two declarations for a function with C
language linkage with the same function name (ignoring the
namespace names that qualify it) that appear in different
namespace scopes refer to the same function.

</BLOCKQUOTE>

<P>For example:</P>

<PRE>
  template &lt;typename T&gt; struct A { struct B; };

  extern "C" {
  template &lt;typename T&gt;
  struct A&lt;T&gt;::B {
   friend void f(B *) requires true {} //<SPAN style="font-family:Times;font-style:italic"> C language linkage applies</SPAN>
  };
  }

  namespace Q {
   extern "C" void f(); //<SPAN style="font-family:Times;font-style:italic"> ill-formed redeclaration?</SPAN>
  }
</PRE>

<P><B>Proposed resolution (April, 2020):</B></P>

<P>Change 9.11 [dcl.link] paragraph 5 as follows:</P>

<BLOCKQUOTE>

...A C language linkage is ignored in determining the
language linkage of the names of class members<SPAN style="font-weight:bold;background-color:#A0FFA0">, the
names of friend functions with a
trailing <I>requires-clause</I>,</SPAN> and the function type
of class member functions...

</BLOCKQUOTE>

<BR><BR><HR><A NAME="2461"></A><H4>2461.
  
Diagnosing non-<TT>bool</TT> type constraints
</H4><B>Section: </B>13.8&#160; [temp.res]
 &#160;&#160;&#160;

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

 <B>Submitter: </B>Hubert Tong
 &#160;&#160;&#160;

 <B>Date: </B>2929-04-20




<P>Given the following example,</P>

<PRE>
  template &lt;typename T&gt; struct A {};
  template &lt;typename T&gt; void f() requires (sizeof(A&lt;T&gt;)) {}
</PRE>

<P>the current wording does not appear to allow diagnosis
of the program as ill-formed. In particular, 13.8 [temp.res]
bullet 8.2 says,</P>

<BLOCKQUOTE>

<P>The program is ill-formed, no diagnostic required, if:</P>

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

<LI><P>no substitution of template arguments into
a <I>type-constraint</I> or <I>requires-clause</I> would
result in a valid expression, or</P></LI>

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

</UL>

</BLOCKQUOTE>

<P>However, substitution into the <I>requires-clause</I>
in this case would result in a valid expression, but not
one that is an atomic constraint that can be checked for
satisfaction.</P>

<P><B>Proposed resolution (April, 2020):</B></P>

<P>Change bullet 8.2 of 13.8 [temp.res] as follows:</P>

<BLOCKQUOTE>

<P>The program is ill-formed, no diagnostic required, if:</P>

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

<LI><P><SPAN style="text-decoration:line-through;background-color:#FFA0A0">no substitution of template arguments into
a <I>type-constraint</I> or <I>requires-clause</I> would
result in a valid expression</SPAN> <SPAN style="font-weight:bold;background-color:#A0FFA0">any
<I>constraint-expression</I> in the program, introduced
or otherwise, has (in its normal form) an atomic constraint
<I>A</I> where no satisfaction check of <I>A</I> could be
well-formed and no satisfaction check of <I>A</I> is
performed</SPAN>, or</P></LI>

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

</UL>

</BLOCKQUOTE>

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