<html>
<head>
<title>P1131R2: Core Issue 2292: simple-template-id is ambiguous between class-name and type-name</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .new { text-decoration:none; font-weight:bold; background-color:#D0FFD0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }
  strong { font-weight: inherit; color: #2020ff }
  #xins:checked ~ * ins { display:none; visibility:hidden }
  #xdel:checked ~ * del { display:none; visibility:hidden }
</style>

</head>

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

<input type="checkbox" id="xins"/><label for="xins">Hide inserted text</label>
<input type="checkbox" id="xdel"/><label for="xdel">Hide deleted text</label>

<h1>P1131R2: Core Issue 2292: simple-template-id is ambiguous between class-name and type-name</h1>

This paper presents the wording changes to resolve core issue 2292.
The issue description says:

<blockquote>
  The grammar term <em>simple-template-id</em> is used
  in the definition of both <em>class-name</em> (12 [class] paragraph 1) and
  <em>type-name</em> (10.1.7.2 [dcl.type.simple] paragraph 1).
  The latter case is intended to apply to alias template specializations.
  It would be helpful to have separate grammar terms for these uses.
</blockquote>

As directed by CWG, this paper restricts the use of the grammar
term <em>class-name</em> to situations where the identifier introduced
in a <em>class-head</em> is named. This mostly applies to
declarations of classes, constructors, and destructors. Furthermore,
the grammar for pseudo-destructor calls is integrated into the grammar
for regular destructor calls.

<h2>Changes relative to P1131R0</h2>
<ul>
  <li>Adjust to section renumbering</li>
  <li>Added change to clause 10 [class] paragraph 1</li>
</ul>
  

<h2>Proposed wording</h2>
  
Change 6.4.5 [basic.lookup.classref] paragraph 2:

<blockquote>
If the <em>id-expression</em> in a class member access (8.5.1.5) is an
<em>unqualified-id</em>, and the type of the object expression is of a
class type C, the <em>unqualified-id</em> is looked up in the scope of
class C. <del>For a pseudo-destructor call (8.5.1.4), the
unqualified-id is looked up in the context of the complete
  postfix-expression.</del>
<p>
If <em>the unqualified-id</em> is ~ <em>type-name</em>,
the <em>type-name</em> is looked up in the context of the entire
<em>postfix-expression</em>.  If the type T of the object expression
is of a class type C, the <em>type-name</em> is also looked up in the
scope of class C. At least one of the lookups shall find a name that
refers to cv T. [ Example: ... ]
</blockquote>

Change in 7.5.4.1 [expr.prim.id.unqual] paragraph 1:

<blockquote>
<pre>
<em>unqualified-id:
     identifier
     operator-function-id
     conversion-function-id
     literal-operator-id
     ~ <del>class-name</del> <ins>type-name</ins>
     ~ decltype-specifier
     template-id</em>
</pre>
... [ Note: For <em>operator-function-id</em>s, see 16.5;
for <em>conversion-function-id</em>s, see 15.3.2;
for <em>literal-operator-id</em>s, see 16.5.8;
for <em>template-id</em>s, see 17.2. A <del><em>class-name</em></del> <ins><em>type-name</em></ins> or
<em>decltype-specifier</em> prefixed by ~ denotes <del>a</del> <ins>the</ins> destructor <ins>of the type so named</ins>; see
<del>15.4 [class.dtor]</del> <ins>7.5.4.3 [expr.prim.id.dtor]</ins>.
Within the definition of a non-static member
function, an identifier that names a non-static member is transformed
to a class member access expression (12.2.2). -- end note ]
</blockquote>
  
Change in 7.5.4.2 [expr.prim.id.qual] paragraph 2:

<blockquote>
  ... Where <del><em>class-name</em> <code>::~</code> <em>class-name</em></del>
<ins><em>type-name</em> <code>::~</code> <em>type-name</em></ins> is
used, the two <del><em>class-name</em>s</del> <ins><em>type-name</em>s</ins>
shall refer to the same <del>class</del> <ins>type (ignoring cv-qualifications)</ins>;
this notation <del>names</del> <ins>denotes</ins> the destructor <ins>of the type so named</ins> <del>(15.4 [class.dtor])</del> <ins>(7.5.4.3 [expr.prim.id.dtor])</ins>. <del>The form
~ <em>decltype-specifier</em> also denotes the destructor, but it
shall not be used as the</del> <ins>The</ins> <em>unqualified-id</em> in
a <em>qualified-id</em> <ins>shall not be of the
form ~ <em>decltype-specifier</em></ins>.
<del>[ Note: A <em>typedef-name</em> that names a class is
a <em>class-name</em> (12.1). -- end note ]</del>

</blockquote>

Add a new section 7.5.4.3 [expr.prim.id.dtor]:

<blockquote class="new">
<b>7.5.4.3 Destruction [expr.prim.id.dtor]</b>
<p>
An <em>id-expression</em> that denotes the destructor of a type T names
the destructor of T if T is a class type (10.3.7 [class.dtor]), otherwise
the <em>id-expression</em> is said to name a <em>pseudo-destructor</em>.
<p>
If the <em>id-expression</em> names a pseudo-destructor,
T shall be a scalar type and
the <em>id-expression</em> shall appear as the right operand of a
class member access (7.6.1.5 [expr.ref]) that forms
the <em>postfix-expression</em> of a function call (7.6.1.2
[expr.call]).  [ Note: Such a call has no effect. -- end note ]
<p>
[ Example:
<pre>
  struct C { };
  void f()
  {
    C * pc = new C;
    using C2 = C;
    pc->C::~C2();     // ok, destroys *pc
    C().C::~C();      // undefined behavior: temporary of type C destroyed twice
    using T = int;
    0 .T::~T();       // ok, no effect
    0.T::~T();        // error: 0. is a floating-point literal (5.13.4 [lex.fcon])
  }
</pre>
-- end example ]
</blockquote>


Change in 7.6.1 [expr.post] paragraph 1:

<blockquote>
<pre><em>postfix-expression:
       primary-expression
       postfix-expression [ expr-or-braced-init-list ]
       postfix-expression ( expression-list<sub>opt</sub> )
       simple-type-specifier ( expression-list<sub>opt</sub> )
       typename-specifier ( expression-list<sub>opt</sub> )
       simple-type-specifier braced-init-list
       typename-specifier braced-init-list
       postfix-expression . template<sub>opt</sub> id-expression
       postfix-expression -> template<sub>opt</sub> id-expression
       <del>postfix-expression . pseudo-destructor-name
       postfix-expression -> pseudo-destructor-name</del>
       postfix-expression ++
       postfix-expression --
       dynamic_cast &lt; type-id > ( expression )
       static_cast &lt; type-id > ( expression )
       reinterpret_cast &lt; type-id > ( expression )
       const_cast &lt; type-id > ( expression )
       typeid ( expression )
       typeid ( type-id )
expression-list:
       initializer-list
<del>pseudo-destructor-name:
       nested-name-specifier<sub>opt</sub> type-name :: ~ type-name
       nested-name-specifier template simple-template-id :: ~ type-name
       ~ type-name
       ~ decltype-specifier</del></em>
</pre>
</blockquote>

Change in 7.6.1.2 [expr.call] paragraph 3:

<blockquote>
If the <em>postfix-expression</em> <del>designates</del>
<ins>names</ins> a destructor <del>(10.7.3 [expr.dtor])</del> <ins>or
pseudo-destructor (7.5.4.3 [expr.prim.id.dtor])</ins>, the type of the
function call expression is void; otherwise, the type of the function
call expression is the return type of the statically chosen function
(i.e., ignoring the virtual keyword), even if the type of the function
actually called is different. This return type shall be an object
type, a reference type or cv void.
<ins>If the <em>postfix-expression</em> names a pseudo-destructor,
the function call has no effect.</ins>
</blockquote>

Remove all of 7.6.1.4 [expr.pseudo]:

<blockquote>
<del>The use of a pseudo-destructor-name after a dot . or arrow -> operator
represents the destructor for the non-class type denoted by type-name
or decltype-specifier. The result shall only be used as the operand
for the function call operator (), and the result of such a call has
type void. The only effect is the evaluation of the postfix-expression
before the dot or arrow.</del>
  <p>
<del>The left-hand side of the dot operator shall be of scalar type. The
left-hand side of the arrow operator shall be of pointer to scalar
type. This scalar type is the object type. The cv-unqualified versions
of the object type and of the type designated by the
pseudo-destructor-name shall be the same type. Furthermore, the two
type-names in a pseudo-destructor-name of the form</del>
<pre>
  <del><em>nested-name-specifier<sub>opt</sub> type-name :: ~ type-name</em></del>
</pre>
<del>shall designate the same scalar type (ignoring cv-qualification).</del>
</blockquote>

Change in 7.6.1.5 [expr.ref] paragraphs 1-3:

<blockquote>
A postfix expression followed by a dot . or an arrow ->, optionally
followed by the keyword template (17.2), and then followed by an
id-expression, is a postfix expression. The postfix expression before
the dot or arrow is evaluated; [ Footnote: ... ] the result of that
evaluation, together with the id-expression, determines the result of
the entire postfix expression.
<p>
For the first option (dot) the first expression shall be a glvalue
<del>having class type</del>. For the second option (arrow)
the first expression shall be a prvalue having pointer <del>to
class</del> type. <del>In both cases, the class type shall
be complete unless the class member access appears in the definition
of that class. [ Note: If the class is incomplete, lookup in the
complete class type is required to refer to the same declaration
(6.3.7). -- end note ]</del> The expression E1->E2 is converted to the
equivalent form (*(E1)).E2; the remainder of 8.5.1.5 will address only
the first option (dot). [ Footnote: ... ]
<p>
<ins>Abbreviating <em>postfix-expression</em>.<em>id-expression</em>
as E1.E2, E1 is called the <em>object expression</em>.  If the object
expression is of scalar type, E2 shall name the pseudo-destructor of that same
type (ignoring cv-qualifications) and E1.E2 is an lvalue of
type "function of () returning void".  [ Note: This value can only be used for a
notional function call (7.5.4.3 [expr.prim.id.dtor]). -- end note
]</ins>
<p>
<ins>Otherwise, the object expression shall be of class type.  The
class type shall be complete unless the class member access appears in
the definition of that class. [ Note: If the class is incomplete,
lookup in the complete class type is required to refer to the same
declaration (6.3.7). -- end note ] The</ins>
  
<del>In either case, the</del> <em>id-expression</em> shall
name a member of the class or of one of its base classes. [ Note:
Because the name of a class is inserted in its class scope (Clause
12), the name of a class is also considered a nested member of that
class. -- end note ] [ Note: 6.4.5 describes how names are looked up
after the . and -> operators. -- end note ]
<p>
<del>Abbreviating postfix-expression.id-expression as E1.E2, E1 is
called the <em>object expression</em></del>. If E2 is a bit-field,
E1.E2 is a bit-field. The type and value category of E1.E2 are
determined as follows. In the remainder of 8.5.1.5, cq represents
either const or the absence of const and vq represents either volatile
or the absence of volatile. cv represents an arbitrary set of
cv-qualifiers, as defined in 6.7.3.
</blockquote>

Change in 7.6.2.1 [expr.unary.op] paragraph 10:

<blockquote>
The operand of ~ shall have integral or unscoped enumeration type; the
result is the ones' complement of its operand. Integral promotions are
performed. The type of the result is the type of the promoted operand.
There is an ambiguity in the grammar when ~ is followed by a
<del><em>class-name</em></del> <ins><em>type-name</em></ins>
or <em>decltype-specifier.</em> The ambiguity is resolved by treating
~ as the unary complement operator rather than as the start of an
<em>unqualified-id</em> naming a destructor.  [ Note: Because the
grammar does not permit an operator to follow the ., ->, or :: tokens,
a ~ followed by
a <del><em>class-name</em></del> <ins><em>type-name</em></ins>
or <em>decltype-specifier</em> in a member access expression
or <em>qualified-id</em> is unambiguously parsed as a destructor
name. -- end note ]

</blockquote>

Change in 9.1.3 [dcl.typedef] paragraph 1:

<blockquote>
<pre>
<em>typedef-name:
      identifier
      <ins>simple-template-id</ins></em>
</pre>
A name declared with the <code>typedef</code> specifier becomes a
<em>typedef-name</em>. <del>Within the scope of its declaration,
a <em>typedef-name</em> is syntactically equivalent to
a keyword and</del> <ins>A <em>typedef-name</em></ins> names
the type associated with
the <del>identifier</del> <ins><em>identifier</em> (9.2
[dcl.decl]) or <em>simple-template-id</em> (Clause 12
[temp])</ins> <del>in the way described in 9.2
[dcl.decl]. A</del> <ins>; a</ins> <em>typedef-name</em> is thus a
synonym for another type. A <em>typedef-name</em> does not introduce a
new type the way a class declaration (10.2 [class.name]) or enum
declaration <ins>(9.6 [dcl.enum])</ins> does. [ Example: ... ]

</blockquote>

<strong>Change in 9.1.3 [dcl.typedef] paragraph 8:</strong>

<blockquote>
<ins>A <em>simple-template-id</em> is only a <em>typedef-name</em>
if its <em>template-name</em> names an alias template or
a template <em>template-parameter</em>.
</ins>
[ Note: <ins>A <em>simple-template-id</em> that names a class template
specialization is a <em>class-name</em> (10.2
[class.name]).</ins> <del>A <em>typedef-name</em> that names a class
type, or a cv-qualified version thereof, is also a <em>class-name</em>
(10.2 [class.name]).</del> If a <em>typedef-name</em> is used to
identify the subject of an <em>elaborated-type-specifier</em>
(9.1.7.3), a class definition (Clause 10 [class]), a constructor
declaration (10.3.4 [class.ctor]), or a destructor declaration (10.3.7
[class.dtor]), the program is ill-formed. -- end note ] [ Example:
... ]

  </blockquote>

Change in 9.1.7.2 [dcl.type.simple] paragraph 1:

<blockquote>
<pre>
<em>type-name:
      class-name
      enum-name
      typedef-name
      <del>simple-template-id</del></em>
</pre>
</blockquote>

Change in 9.1.7.3 [dcl.type.elab] paragraph 2:

<blockquote>
<ins>[ Note:</ins> 6.4.4 [basic.lookup.elab] describes how name lookup
proceeds for the <em>identifier</em> in
an <em>elaborated-type-specifier</em>. <ins>-- end note ]</ins> If
the <em>identifier</em> <ins>or <em>simple-template-id</em></ins>
resolves to a <em>class-name</em> or <em>enum-name</em>,
the <em>elaborated-type-specifier</em> introduces it into the
declaration the same way a <em>simple-type-specifier</em> introduces
its <em>type-name</em> <ins>(9.1.7.2 [dcl.type.simple]).</ins> If
the <em>identifier</em> <ins>or <em>simple-template-id</em></ins>
resolves to a <em>typedef-name</em> <del>or
the <em>simple-template-id</em> resolves to an alias template
specialization</del> <ins>(9.1.3 [dcl.typedef], 12.2
[temp.names])</ins>, the <em>elaborated-type-specifier</em></del> is
ill-formed.  [ Note:d This implies that, within a class template with a
template <em>type-parameter</em> T, the declaration <code>friend class
T;</code> is ill-formed. However, the similar declaration <code>friend
T;</code> is allowed (10.8.3 [class.friend]). -- end note ]
</blockquote>

Change 10.2 [class.name] paragraph 5:

<blockquote>
<ins>A <em>simple-template-id</em> is only a <em>class-name</em> if
its <em>template-name</em> names a class template.</ins>
<del>A <em>typedef-name</em> (9.1.3 [dcl.typedef]) that names a class
type, or a cv-qualified version thereof, is also
a <em>class-name</em>. If a <em>typedef-name</em> that names a
cv-qualified class type is used where a <em>class-name</em> is
required, the cv-qualifiers are ignored. A <em>typedef-name</em> shall
not be used as the identifier in a <em>class-head</em>.</del>
</blockquote>

Change in 10.6 [class.derived] paragraph 1:

<blockquote>
<pre>
<em>class-or-decltype:
    nested-name-specifier<sub>opt</sub> <del>class-name</del> <ins>type-name</ins>
    nested-name-specifier <code>template</code> simple-template-id
    decltype-specifier</em>
</pre>
</blockquote>

Change in 10.6 [class.derived] paragraph 2:

<blockquote>
A <em>class-or-decltype</em> shall denote a <ins>(possibly
cv-qualified)</ins> class type that is not an incompletely defined
class (<del>Clause 10</del><ins>10.3 [class.mem]</ins>)<ins>;
any cv-qualifiers are ignored</ins>.
The class denoted by the <em>class-or-decltype</em> of a <em>base-specifier</em> is called a direct base class for the class being defined.
...

<del>If the name found is not a <em>class-name</em>, the program is ill-formed.</del>
</blockquote>

Change in 10.3.4 [class.ctor] paragraph 1:

<blockquote>
<del>The <em>class-name</em> shall not be
a <em>typedef-name</em>.</del> In a constructor declaration, each
<em>decl-specifier</em> in the optional <em>decl-specifier-seq</em>
shall be friend, inline, explicit, or constexpr. [ Example: ... ]
</blockquote>

Change in 10.3.7 [class.dtor] paragraph 1:

<blockquote>
<del>The <em>class-name</em> shall not be
a <em>typedef-name</em>.</del>  A destructor shall take no arguments
(11.3.5). Each <em>decl-specifier</em> of
the <em>decl-specifier-seq</em> of a destructor declaration (if any)
shall be friend, inline, or virtual.

</blockquote>

<strong>Merge and change in 12.2 [temp.names] paragraphs 6 and 7:</strong>

<blockquote>
<ins>[ Note:</ins> A <em>simple-template-id</em> that names a class
template specialization is a <em>class-name</em> (<del>Clause 10
[class]</del><ins>10.2 [class.name]</ins>).
<ins>Any other <em>simple-template-id</em> that names a type
  is a <em>typedef-name</em>.</ins> <del>[ Note: This
rule disambiguates parsing of <em>simple-template-id</em>s
between <em>class-name</em> and <em>typedef-name</em>.</del> -- end note
]
<p>
<del>A <em>template-id</em> 
that names an alias template specialization is
a <em>type-name</em>.</del>

</blockquote>

Change in A.1 [gram.key] paragraph 1:

<blockquote>
  <pre>
<em>typedef-name:
    identifier
    <ins>simple-template-id</ins>
</blockquote>

</body>
</html>
