[cfe-dev] extern array as non-type template argument with clang c++1z ?

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Mon Aug 28 18:54:09 PDT 2017


On 28 August 2017 at 14:36, Shuo Chen via cfe-dev <cfe-dev at lists.llvm.org>
wrote:

> Dear clang folks,
>
> Does C++17 allow using extern array as non-type template argument?
>
> Clang gives error when compiling follow code: https://godbolt.org/g/66vRKR
>
> template <const char* T>
> struct X {
> };
>
> extern const char tag[];
> typedef X<tag> Y;
>
> When compiling with clang from trunk @311886:
>
> $ clang++ nontype.cc -std=c++1z
> nontype.cc:6:11: error: non-type template argument refers to subobject
> '&tag'
> typedef X<tag> Y;
>           ^
> 1 error generated.
>

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:

http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#2043

... and clang even implements that resolution, but it doesn't fire for your
testcase.

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.

Thanks for the report!


> I found a similar question on SO: https://stackoverflow.com/
> questions/38147062
>
> I traced the code a little bit, the error was emitted by
> Sema::CheckTemplateArgument() at
> https://github.com/llvm-mirror/clang/blob/0a0eebabaad89213cd79fe9947fbb4
> 49484b6efd/lib/Sema/SemaTemplate.cpp#L6054
> Where we have Value.hasLValuePath() == false for extern array.
>
> The code works fine in C++98/11/14 mode with clang, as well as
> -std=c++17 with g++.
>
> I also tried using a non-extern array:
>
> const char tag[] = "abc";
> struct Z {
>   X<tag> x_;
> };
>
> But g++ (6/7) complains with "warning: 'Z' has a field 'Z::x_' whose
> type uses the anonymous namespace [-Wsubobject-linkage]"
>
> See https://gist.github.com/chenshuo/ed35a5615d6696be4b65a74515d598e2,
> this warning only appears when array 'tag' is in defined in header
> file. So I could not post a link to online compiler here.
>
> Finally, I tried extern array with initialization:
>
> extern const char tag[] = "abc";
>
> Both clang and g++ compile fine, but I got linker error of duplicated
> symbol: multiple definition of `tag'.
>
> What is the correct way of using array as non-type template argument
> in C++17?  Thanks in advance!


There are a couple of workarounds for this issue. If you specify the array
bound, Clang will accept:

extern const char tag[4];
typedef X<tag> Y;

Alternatively, you can declare the variable inline:

extern inline const char tag[] = "abc";

(You will need to make this change to every declaration of the variable.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170828/6e30d06d/attachment.html>


More information about the cfe-dev mailing list