<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 28 August 2017 at 14:36, Shuo Chen via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Dear clang folks,<br>
<br>
Does C++17 allow using extern array as non-type template argument?<br>
<br>
Clang gives error when compiling follow code: <a href="https://godbolt.org/g/66vRKR" rel="noreferrer" target="_blank">https://godbolt.org/g/66vRKR</a><br>
<br>
template <const char* T><br>
struct X {<br>
};<br>
<br>
extern const char tag[];<br>
typedef X<tag> Y;<br>
<br>
When compiling with clang from trunk @311886:<br>
<br>
$ clang++ nontype.cc -std=c++1z<br>
nontype.cc:6:11: error: non-type template argument refers to subobject '&tag'<br>
typedef X<tag> Y;<br>
          ^<br>
1 error generated.<br></blockquote><div><br></div><div>This is "correct" behavior in the sense that Clang is following the standard's rules, but is a bug in the standard wording. (You have my apologies, this was my fault...) There is a proposed resolution for this standard bug:</div><div><br></div><div><a href="http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#2043">http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#2043</a><br></div><div><br></div><div>... and clang even implements that resolution, but it doesn't fire for your testcase.</div><div><br></div><div>The problem turns out to be that clang's constant expression evaluation support does not properly handle array-to-pointer decay on incomplete array types. The rules for such cases are unclear, which is another open bug in the standard; I've implemented the most likely resolution for that standard issue in r311970, and your testcase is now accepted by Clang trunk.</div><div><br></div><div>Thanks for the report!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
I found a similar question on SO: <a href="https://stackoverflow.com/questions/38147062" rel="noreferrer" target="_blank">https://stackoverflow.com/<wbr>questions/38147062</a><br>
<br>
I traced the code a little bit, the error was emitted by<br>
Sema::CheckTemplateArgument() at<br>
<a href="https://github.com/llvm-mirror/clang/blob/0a0eebabaad89213cd79fe9947fbb449484b6efd/lib/Sema/SemaTemplate.cpp#L6054" rel="noreferrer" target="_blank">https://github.com/llvm-<wbr>mirror/clang/blob/<wbr>0a0eebabaad89213cd79fe9947fbb4<wbr>49484b6efd/lib/Sema/<wbr>SemaTemplate.cpp#L6054</a><br>
Where we have Value.hasLValuePath() == false for extern array.<br>
<br>
The code works fine in C++98/11/14 mode with clang, as well as<br>
-std=c++17 with g++.<br>
<br>
I also tried using a non-extern array:<br>
<br>
const char tag[] = "abc";<br>
struct Z {<br>
  X<tag> x_;<br>
};<br>
<br>
But g++ (6/7) complains with "warning: 'Z' has a field 'Z::x_' whose<br>
type uses the anonymous namespace [-Wsubobject-linkage]"<br>
<br>
See <a href="https://gist.github.com/chenshuo/ed35a5615d6696be4b65a74515d598e2" rel="noreferrer" target="_blank">https://gist.github.com/<wbr>chenshuo/<wbr>ed35a5615d6696be4b65a74515d598<wbr>e2</a>,<br>
this warning only appears when array 'tag' is in defined in header<br>
file. So I could not post a link to online compiler here.<br>
<br>
Finally, I tried extern array with initialization:<br>
<br>
extern const char tag[] = "abc";<br>
<br>
Both clang and g++ compile fine, but I got linker error of duplicated<br>
symbol: multiple definition of `tag'.<br>
<br>
What is the correct way of using array as non-type template argument<br>
in C++17?  Thanks in advance!</blockquote><div><br></div><div>There are a couple of workarounds for this issue. If you specify the array bound, Clang will accept:</div><div><br></div><div>extern const char tag[4];</div><div>typedef X<tag> Y;</div><div><br></div><div>Alternatively, you can declare the variable inline:</div><div><br></div><div>extern inline const char tag[] = "abc";</div><div><br></div><div>(You will need to make this change to every declaration of the variable.)</div></div></div></div>