<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><style>
ins {background-color:#A0FFA0}
del {background-color:#FFA0A0}
strong { color: #2020ff }
#hidedel:checked ~ * del, #hidedel:checked ~ * del * { display:none; visibility:hidden }
</style> 
<title>P2115R0: US069: Merging of multiple definitions
for unnamed unscoped enumerations</title>
</head><body>
ISO/IEC JTC1 SC22 WG21 P2109R0<br>
    Nathan Sidwell<br>
    Target audience: CWG, Plenary<br>
2020-02-14

<h1>P2115R0: US069: Merging of multiple definitions for unnamed unscoped enumerations</h1>
<p>This paper resolves NB Comment US069:</p>
<blockquote>Unnamed unscoped enumerations may be defined in multiple header
  units, and have no linkage. The merging rules of multiple
  definitions from header units or appearing textually outside of
  module purview require implementations to determine if two
  particular definitions are for the same entity. There is no
  mechanism specified to determine whether two such enumerations are
  for the same entity. Unnamed, untypedefed, enums are common in
  header files, as the enumeration values also appear in the
  containing (namespace) scope.<br>
  A mechanism should be specified.</blockquote>

<blockquote>Proposed change:<br>
Use the first enumerator as the key. If two unnamed unscoped
  enumeration definitions in the same scope have the same identifier
  for their first enumerator, they are defining the same enumerated
  type. (It therefore is an ODR violation if the enumerators are not
  the same.) FYI this is the heuristic independently implemented in the
  Clang Modules extension and GCC C++ Modules. It is expected in Clang
  C++ Modules.</blockquote>

<h2>Discussion:</h2>

<p>This is an existing ODR problem, made more pressing by modules.
  EWG attempted guidance:</p>

<dl>
  <dt>Use the names of the first enumerator to merge enum types
    across translation units, as recommended by US069</dt>
  <dd>SF:1 F:5 N:4 A:2 SA:3. Not consensus</dd>
  <dt>Treat the enumerators of anonymous enums as the underlying
    type, as in C</dt>
  <dd>SF:0 F:1 N:2 A:5 SA:8 Not consensus</dd>
</dl>

<p>EWG was concerned that the second option would not permit using an
enumerator of an anonymous enum as a deduced (or decltyped) template
type parameter:
</p><blockquote><code>template&lt;auto V&gt; int Frob () {return int (V);}<br>
enum { A = 195'936'478 };<br>
template int Frob&lt;A&gt; ();</code></blockquote>

<p>This is already an ODR violation, and GCC, Clang and MSVC++ all
produce different, clearly broken, manglings for the instantiation.  In
GCC's case it is '_Z4FrobIL8._anon_0195936478EEiv', exposing the internal
anonymous identifier.  Clang simularly exposes an internal
counter-generated name.  MSVC++, I believe, attempts to produce a
globally unique identifier.  If any existing code is doing this, it is
very brittle!</p>

<p>EWG does request the creation of a CWG issue and we recommend that
  issue be resolved as a DR.</p>

<p>CWG requested drafting for the mechanism proposed in US069 (the
first of the above two options).</p>

<p>This suggests that for:
</p><blockquote><code>namespace X { enum { A }; }</code></blockquote>
<p>the enum type would be mangled as <code>_ZN1X1AE</code> (to pick an
ABI at random).  Fortunately that ABI never needs to mangle the
enumerator itself -- when encoded as template value parameters a
type/integral value pair is used.
</p>

<p>Core discussed this direction in Prague, and was concerned that two
  different (non-header) translation units may define anonymous enums
  (for instance `<tt>enum { INIT, &hellip; };</tt>') that now become
  an ODR violation, whereas before they did not &mdash; they had
  internal linkage.  This would also apply to an anonymous enum that
  had enumerators added in a version2 header.  Thus changes to the ODR
  rules were also requested.</p>

<h2>Wording:</h2>

<p>Alter [basic.def.odr] (6.3) para 12:</p> 

<p>In the first part of the paragraph &hellip;</p>
 
<blockquote>
  There can be more than one definition of a<br>
  <blockquote>
&mdash; class type (Clause 11),<br>
&mdash; enumeration type (9.7.1),<br>
&mdash; inline function or variable (9.2.7),<br>
&mdash; templated entity (13.1),<br>
&mdash; default argument for a parameter (for a function in a given
scope) (9.3.3.6), or<br>
&mdash;  default template argument (13.2)<br>
  </blockquote>

in a program provided that each definition appears in a different
translation unit, and <del>provided</del> the definitions satisfy the
following requirements. <del>There shall not be more than one
definition of an entity that is attached to a named module (10.1); no
diagnostic is required unless a prior definition is reachable at a
point where a later definition appears.</del> Given such an
entity <del>named</del> D defined in more than one translation
unit<ins>, for all
definitions of D, or, if D is unnamed enumeration, for all definitions
of D that are reachable at each program point, </ins> <del>all
of</del> the following requirements shall be satisfied.

<blockquote><ins>&mdash; Each such definition of D shall not be
    attached to a named module (10.1).</ins><br>

  &mdash; Each <ins>such</ins> definition of D shall consist of the
    same sequence of tokens, where the definition of a closure type is
    considered to consist of the sequence of tokens of the
    corresponding <em>lambda-expression</em>.<br>
&mdash; &hellip;
</blockquote>
</blockquote>

<p>Editing instruction:  alter each item in the bulleted list as:
  <blockquote>&mdash; Each <ins>such</ins> definition of D</blockquote>

<p>Split the block of the paragraph following bullet 12.14, (creating a
  new paragraph):</p>

  <blockquote>
If D is a template and is defined in more than one translation unit,
then the preceding requirements shall apply both to names from the
template’s enclosing scope used in the template definition (13.8.3),
and also to dependent names at the point of instantiation
(13.8.2). These requirements also apply to corresponding entities
defined within each definition of D (including the closure types of
<em>lambda-expression</em>s, but excluding entities defined within
default arguments or default template arguments of either D or an
entity not defined within D). For each such entity and for D itself,
the behavior is as if there is a single entity with a single
definition, including in the application of these requirements to
other entities. [<em>Note</em>: The entity is still declared in
multiple translation units, and 6.6 still applies to these
declarations. In particular, lambda- expressions (7.5.5) appearing in
the type of D may result in the different declarations having distinct
types, and lambda-expressions appearing in a default argument of D may
still denote different types in different translation units. &mdash;
<em>end note</em>]</blockquote>

<blockquote>If <del>the</del><ins>these</ins> definitions <del>of
D</del> do not satisfy these requirements, then the program is
ill-formed<ins>; a diagnostic is required only if the entity is
attached to a named module and a prior definition is reachable at the
point where a later definition occurs.</ins> [<em>Example</em>:
...</blockquote>

<p>Insert a new paragraph after the example at the end of
[basic.def.odr] para 12:</p>

<blockquote><ins>If, at any point in the program, there is more than
one reachable unnamed enumeration definition in the same scope that
have the same first enumerator name and do not have typedef names for
linkage purposes (9.7.1), those unnamed enumeration types shall be the
same; no diagnostic required</ins>
</blockquote>

<p>Add to the bullet list in [basic.link] (6.6) para 5:
</p><blockquote>
  An unnamed namespace or a namespace declared directly or
  indirectly within an unnamed namespace has internal linkage. All
  other namespaces have external linkage. A name having namespace
  scope that has not been given internal linkage above and that is the
  name of
  <blockquote>
  &mdash; a variable; or<br>
  &mdash; a function; or<br>
  &mdash; a named class (11.1), or an unnamed class defined in a
  typedef declaration in which the class has the typedef name for
  linkage purposes (9.2.3); or<br>
  &mdash; a named enumeration (9.7.1), or an unnamed enumeration defined
  in a typedef declaration in which the enumeration has the typedef name
  for linkage purposes (9.2.3); or<br>
  <ins>&mdash; an unnamed enumeration that has an
  enumerator as a name for linkage purposes (9.7.1); or</ins><br>
  &mdash; a template
</blockquote></blockquote>

<p>Alter [basic.link] (6.6) para 10 after the list:</p>

<blockquote>If multiple declarations of the same name with external
linkage would declare the same entity except that they are attached to
different modules, the program is ill-formed; no diagnostic is
required. [<em>Note</em>: <em>using-declaration</em>s, typedef
declarations, and <em>alias-declaration</em>s do not declare entities,
but merely introduce synonyms. Similarly, <em>using-directive</em>s do
not declare entities. <ins>Enumerators do not have linkage, but may
serve as the name of an enumeration with linkage (9.7.1)</ins>
&mdash; <em>end note</em>]</blockquote>

<p>Change [dcl.typedef] 9.2.3 para 9</p>
<blockquote>If the typedef declaration defines an unnamed class
<del>(or enum)</del><ins>or enumeration</ins>, the first typedef-name
declared by the declaration to be that <del>class</del> type <del>(or
enum type)</del> is used to denote the <del>class</del> type <del>(or
enum type)</del> for linkage purposes only (6.6).</blockquote>

<p>Alter [dcl.enum] (9.7.1) para 11:</p>
<blockquote> Each <em>enum-name</em> and each
unscoped <em>enumerator</em> is declared in the scope that immediately
contains the <em>enum-specifier</em>. Each scoped enumerator is
declared in the scope of the enumeration. <ins>An unnamed enumeration
that does not have a typedef name for linkage purposes (9.2.3) and
that has a first enumerator is denoted, for linkage purposes (6.6), by
its underlying type and its first enumerator; such an enumeration is
said to have an enumerator as a name for linkage purposes.
</ins> These names obey the scope rules defined for all names in
6.4 and 6.5. <ins>[<em>Note</em>: Each unnamed enumeration with no
enumerators is a distinct type. &mdash; <em>end note</em>]</ins>
</blockquote>

</body></html>
