Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Static constexpr string struct causes unresolved symbols on Windows #42250

Closed Quuxplusone closed 5 years ago

Quuxplusone commented 5 years ago
Bugzilla Link PR43280
Status RESOLVED FIXED
Importance P normal
Reported by Tom Hender (ToHe_EMA@gmx.de)
Reported on 2019-09-11 09:44:19 -0700
Last modified on 2019-09-11 15:37:20 -0700
Version trunk
Hardware PC All
CC blitzrakete@gmail.com, dgregor@apple.com, erik.pilkington@gmail.com, htmldeveloper@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk, rnk@google.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
We are currently exploring to compile our software on Windows with Clang, but
hit a couple Clang/LLVM bugs along the way. Using a static constexpr string in
a struct/class results in unresolved symbols when linking. The minimal code
needed to trigger the bug looks like this:
struct Struct
{
    static constexpr char const* ConstexprVar = "Test";
    char const* const* Do() { return &ConstexprVar; }
};
int main() { Struct().Do(); }

It is simply compiled with "clang++ Main.cpp" without further options which
then results in this error:
>Main-70a406.o : error LNK2019: unresolved external symbol "public: static char
const * const Struct::ConstexprVar" >(?ConstexprVar@Struct@@2QEBDEB) referenced
in
> function "public: char const * const * __cdecl Struct::Do(void)"
(?Do@Struct@@QEAAPEBQEBDXZ)
>Main.o : fatal error LNK1120: 1 unresolved externals
>clang++: error: linker command failed with exit code 1120 (use -v to see
invocation)

When trying to link with lld, the result is the same:
>lld: error: undefined symbol: public: static char const *const
Struct::ConstexprVar
>>> referenced by Main.o:(public: char const *const * __cdecl Struct::Do(void))

At least the current stable release 8.0 and the nightly build (from here
https://llvm.org/builds/) are affected.
Quuxplusone commented 5 years ago
Formally, this code is invalid: prior to C++17, static data members whose
addresses are used are required to be defined outside the class. You are
missing such a definition, which would look like this:

const char *const Struct::ConstexprVar;

(Or you can use -std=c++17 to enable C++17 mode, in which this code is valid
without an out-of-line definition.)

That said... it's my understanding that the MS C++ ABI expects a definition for
Struct::ConstexprVar to be implicitly synthesized in every compilation that
uses it, rather than requiring an out-of-line definition. It looks like we only
do this for variables of integral or enumeration type currently, which I think
is a bug.
Quuxplusone commented 5 years ago

Coincidentally, I think https://reviews.llvm.org/D47956 will fix this by making these constexpr things inline even in pre C++17 modes. See issue 36125 as a potential dupe.

Quuxplusone commented 5 years ago

r371642