<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>P2788R0: Linkage for modular constants</title>
  <style type="text/css">
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
  </style>
  <style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
  { position: relative; }
pre.numberSource a.sourceLine:empty
  { position: absolute; }
pre.numberSource a.sourceLine::before
  { content: attr(data-line-number);
    position: absolute; left: -5em; text-align: right; vertical-align: baseline;
    border: none; pointer-events: all;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <style type="text/css">
  div.del, section.del { background: #fcd; }
  div.ins, section.ins { background: #bfa; }
  .mv { background: #ddf; }
  s, .del { background: #ff8888; margin-right: 0.15ch; }
  u, .ins { background: #88ff88; }
  /* from https://stackoverflow.com/a/32456613 */
  div > blockquote, body > blockquote {
      display: list-item;
      list-style-type: "- ";
  }
  /* With a 3 em gutter and two columns, ANSI letter is 127 characters wide. */
  pre {
  		margin-left: 1.2em;
  }
  .tony {
    border-collapse: collapse;
  }
  .tony > tbody > tr {
    vertical-align: top;
  }
  tr.hr, tr.hr {
    border-bottom: thin solid #60a0b0;  /* relies on collapse */
  }
  </style>
</head>
<body>
<header>
<h1 class="title">P2788R0: Linkage for modular constants<!-- -*- c++-md -*- --></h1>
</header>
<p><em>Audience</em>: EWG<br />
S. Davis Herring &lt;<a href="mailto:herring@lanl.gov">herring@lanl.gov</a>&gt;<br />
Los Alamos National Laboratory<br />
February 8, 2023</p>
<h1 id="introduction">Introduction</h1>
<p>National body comment <a href="https://github.com/cplusplus/nbballot/issues/480">US 8-036</a> points out an unfortunate interaction between C++98 linkage rules and C++20 modules. This paper explains the interaction in more detail, motivates a choice among the suggestions offered by the comment, and provides wording for that choice.</p>
<h2 id="history">History</h2>
<p>C headers typically use macros to define constants:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="pp">#define MAX_BUNNIES 57</span></a>
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="kw">struct</span> bunny bunnies[MAX_BUNNIES];</a></code></pre></div>
<p>C++ allows the use of constant integer variables in constant expressions to avoid the macros:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb2-1" data-line-number="1"><span class="at">const</span> <span class="dt">int</span> max_bunnies=<span class="dv">57</span>;</a>
<a class="sourceLine" id="cb2-2" data-line-number="2">bunny bunnies[max_bunnies];</a></code></pre></div>
<p>If, however, <code>max_bunnies</code> appears in a header file, it might end up being defined more than once. In C++17, we can write</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="dt">int</span> max_bunnies=<span class="dv">57</span>;</a></code></pre></div>
<p>to simply allow such multiple definitions. In the absence of the inline variables feature, the first solution adopted was to give such variables internal linkage ([basic.link]/3.2), such that the multiple definitions are of <em>distinct variables</em>.</p>
<p>It is little surprise that this implicit duplication of variables causes problems with the one-definition rule. First, it requires a special exception ([basic.def.odr]/14.5.1) to allow</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb4-1" data-line-number="1"><span class="at">const</span> <span class="dt">int</span> zero=<span class="dv">0</span>;</a>
<a class="sourceLine" id="cb4-2" data-line-number="2"><span class="kw">inline</span> <span class="dt">int</span> get_zero() {<span class="cf">return</span> zero;}</a></code></pre></div>
<p>to appear in more than one translation unit despite the fact that the multiple definitions of <code>get_zero</code> refer to <em>different</em> variables named <code>zero</code>. Moreover, odr-using such variables enjoys no such affordance:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb5-1" data-line-number="1"><span class="pp">#include</span><span class="im">&lt;algorithm&gt;</span></a>
<a class="sourceLine" id="cb5-2" data-line-number="2"><span class="at">const</span> <span class="dt">int</span> ceiling=<span class="dv">5</span>;</a>
<a class="sourceLine" id="cb5-3" data-line-number="3"><span class="kw">inline</span> <span class="dt">int</span> cap(<span class="dt">int</span> x) {<span class="cf">return</span> <span class="bu">std::</span>min(x,ceiling);}  <span class="co">// oops</span></a></code></pre></div>
<p><code>std::min</code> accepts and returns references, so the different definitions of <code>cap</code> odr-use different <code>ceiling</code> variables and this is IFNDR. (The trap can be avoided by writing <code>+ceiling</code> to produce a temporary, but that does not work in all cases and is more than a little mysterious.)</p>
<p>C++11 allowed constants to be declared as static data members, deeming their declarations to not be definitions despite having initializers. Therefore, they did not need internal linkage, and C++17 was able to make such variables implicitly inline. (Similarly, C++14 introduced variable templates that, since they could be defined more than once, did not need the internal-linkage trick.) Modules do one better: by using a single definition of an entity for all translation units that need a definition of it, there is no need for <code>inline</code> to allow multiple definitions at all. (It still has its original meaning of encouraging the implementation to inline function calls, with the attendant <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1498r1.html#inline">ABI implications</a>.)</p>
<h2 id="problem">Problem</h2>
<p>However, declaring a const-qualified variable in a namespace gives it internal linkage even in a module unit. This prevents it from being used in client translation units:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb6-1" data-line-number="1"><span class="co">// TU #1</span></a>
<a class="sourceLine" id="cb6-2" data-line-number="2">module A:B;</a>
<a class="sourceLine" id="cb6-3" data-line-number="3"><span class="at">const</span> <span class="dt">int</span> dimensions=<span class="dv">3</span>;</a></code></pre></div>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb7-1" data-line-number="1"><span class="co">// TU #2</span></a>
<a class="sourceLine" id="cb7-2" data-line-number="2">module A;</a>
<a class="sourceLine" id="cb7-3" data-line-number="3">import std;</a>
<a class="sourceLine" id="cb7-4" data-line-number="4">import :B;</a>
<a class="sourceLine" id="cb7-5" data-line-number="5"><span class="kw">using</span> vector=<span class="bu">std::</span>array&lt;<span class="dt">double</span>,dimensions&gt;;  <span class="co">// error: lookup failed</span></a></code></pre></div>
<p>(Only clients in the same module are affected, since <code>export</code> assigns external linkage instead.) Moreover, such a variable cannot be used in an inline function or function template that does not itself have internal linkage:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="co">// TU #1</span></a>
<a class="sourceLine" id="cb8-2" data-line-number="2"><span class="kw">export</span> module A;</a>
<a class="sourceLine" id="cb8-3" data-line-number="3"><span class="at">const</span> <span class="dt">double</span> delta=<span class="fl">0.01</span>;</a>
<a class="sourceLine" id="cb8-4" data-line-number="4"><span class="kw">template</span>&lt;<span class="kw">class</span> F&gt;</a>
<a class="sourceLine" id="cb8-5" data-line-number="5"><span class="kw">export</span> <span class="dt">double</span> derivative(F &amp;&amp;f,<span class="dt">double</span> x) {</a>
<a class="sourceLine" id="cb8-6" data-line-number="6">  <span class="cf">return</span> (f(x+delta)-f(x))/delta;</a>
<a class="sourceLine" id="cb8-7" data-line-number="7">}</a></code></pre></div>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb9-1" data-line-number="1"><span class="co">// TU #2</span></a>
<a class="sourceLine" id="cb9-2" data-line-number="2">import A;</a>
<a class="sourceLine" id="cb9-3" data-line-number="3"><span class="dt">double</span> d=derivative([](<span class="dt">double</span> x) {<span class="cf">return</span> x*x;},<span class="dv">2</span>);  <span class="co">// error: names delta</span></a></code></pre></div>
<p>(The <code>get_zero</code> example above works in a module only because of another special rule ([basic.link]/14.4).)</p>
<p>This internal linkage can be avoided by adding <code>inline</code>, <code>extern</code>, or <code>export</code>, but each is confusing in this case:</p>
<ul>
<li><code>inline</code> because its only standard effect is changing the linkage,</li>
<li><code>extern</code> because it’s applied to a definition and grants <em>module</em> linkage rather than external linkage, and</li>
<li><code>export</code> because removing it in other circumstances does not affect clients within the same module.</li>
</ul>
<p>Having to use any of these is an obstacle for converting a header-based library (that defines internal constants without <code>inline</code>) into a module.</p>
<h1 id="proposal">Proposal</h1>
<p>As a defect report against C++20, disable the special case for const-qualified variables in the module purview of importable module units, determining their linkage in the same fashion as for any other variable there. For compatibility, do not change the behavior in non-importable module units: they cannot provide definitions to any other translation unit, and converting existing <em>source</em> files to (non-partition) module implementation units should not introduce conflicts between their internal-linkage constants. (It would of course be trivial to instead apply this change to all of the purview of any named module if desired.)</p>
<p>The obvious argument against such a change is that we do not want distinct language rules for module units and other translation units; EWG has rejected <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0997r0.html">previous proposals</a> suggesting such, despite the obvious benefits for modernization. However, in a practical sense such a distinction is the status quo: a const-qualified global variable in a header file can be used by its clients (albeit with the aforementioned ODR trap), but the same variable declared in an importable module unit cannot be used by its clients at all (nor even by its own inline functions). The fact that, with this change, such a variable changes from internal linkage to module linkage when changing from a header file to a module is part of the feature of avoiding ODR problems by defining things but once.</p>
<h1 id="wording">Wording</h1>
<p>Relative to N4928.</p>
<h2 id="basic.link">#[basic.link]</h2>
<p>Change bullet (3.2):</p>
<blockquote>
<p>a non-template variable of non-volatile const-qualified type, unless</p>
<ol type="1">
<li><u>it is declared in the purview of a module interface unit (outside the <em>private-module-fragment</em>, if any) or module partition, or</u></li>
<li>it is explicitly declared <code>extern</code>, or</li>
<li>it is inline<s> or exported</s>, or</li>
<li>it was previously declared and the prior declaration did not have internal linkage; or</li>
</ol>
</blockquote>
<p>[<em>Drafting note</em>: The <em>private-module-fragment</em> exception follows /17. One could factor out a definition for an “importable declaration” or so. — <em>end drafting note</em>]</p>
</body>
</html>
