-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scalar constexpr is odr-used when used as json initializer #1905
Comments
Can you please provide the full example you are describing? I fail to reproduce the issue with just the class definition above. |
This is an embedded project, so my ability to strip back the example is somewhat limited. Here's what I've done: I've put all of the relevant code into a single source code module (json_test.cc), which I've attached here: The only two files I #include in the test file are
I then include that prototype and invoke that function from somewhere else in my program to make sure it all gets linked. And I still get the linker error. I've included compiler command line details and the exact linker error message in the source file as well. Hopefully you'll spot something. If it still doesn't trigger for you, I could see about working up a full separate example project in MCUXpresso, so that you could then download MCUXpresso for yourself and try building the project. (Since the error I'm encountering is a linker failure, not a runtime failure, you wouldn't need any embedded hardware in order to reproduce the error.) Let me know if you're able to get the error to trigger. |
Fun fact: I've just discovered that regular old assignment triggers this bug for me as well. Example:
I've updated my example code: I thought maybe it would behave differently if it wasn't being used in an initializer list, but apparently not. Hopefully you can reproduce it. If not, I'll work up an MCUXpresso project for you. |
For easier debugging, I have reproduced the issue here on Godbolt: https://godbolt.org/z/WxmL5Q The notable differences are:
The behavior seems to be expected though, as pre- |
Thanks for setting that up @nickaein . I guess I understand the bit about the constructor being defined as taking a const reference, which would demand that the constexpr be instantiated. Presumably Is there a way to address this somehow using rvalue references? Or is this a won't-fix? |
To get back to your question:
That's right, but my guess is that the constructor (initializer_list?) is taking its arguments as const reference. This causes the linker to complain about the Therefore, any trick that helps to prevent nlohmann::json j{{"key", static_cast<decltype(kFoo)>(kFoo)}};
As pointed out in the links above, this is expected (yet not desired) on C++14. This has been "fixed" on C++17 onward. |
Thanks for the analysis @nickaein. I am afraid there is little this library can do, right? |
I agree. Even if we try to detect and handle such cases,
Nevertheless, this seems a "normal" behavior of pre-C++17 compilers and based on the C++ standard, so we shouldn't try to work around that. |
I'm not sure if this is a bug or not; hopefully someone more versed in the JSON library or C++ in general can determine that.
I've run into a situation where I'm using a
constexpr
in a brace initializer for a JSON object, and the linker is complaining that theconstexpr
is an undefined reference. Here's complete example code:Test conditions -- I call
Wibble::Test()
from another module to ensure that all methods are being invoked.Expected behavior -- If the last line
constexpr size_t Wibble::kFoo;
is omitted/commented out, the project compiles and links successfully.Actual behavior -- If the last line shown above is not present, I get a linker error:
my_source_file.cc:32: undefined reference to 'Wibble::kFoo'
My best understanding of what's going on is... I'm expecting that the brace initializer should only need the value of the scalar
kFoo
that is being supplied. But the compiler is acting likekFoo
is "odr-used". That is, it's demanding that there be a static constant "1" in memory identified by the labelWibble::kFoo
.I know that
static constexpr
items need to be defined and not just declared if they're odr-used (more background here), but I don't see why that's the case here. InWibble::GetOne()
, the value 1 is a satisfactory initializer for the JSON object.kFoo
is used in the exact same way inWibble::GetFoo()
, where only its value should be needed, but the compiler is demanding thatWibble::kFoo
be explicitly defined.So, why is using
kFoo
in the initializer list causing it to be odr-used? Presumably if I referenced someconstexpr
from some other module, then thatconstexpr
would need to be defined as well, and I shouldn't be defining storage in one module that belongs to a different module... and I shouldn't need to explicitly define each and every constexpr in all of my classes. IfkFoo
were a complex type, I could understand why it would be need to be odr-used, but it's not, it's a scalar, and only the value of it should be necessary to initialize the object. I'm using C++14, so this shouldn't be an issue for scalars.So, is this expected behavior?
Details:
Using NXP MCUXpresso IDE for Cortex-M processors
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 8-2019-q3-update) 8.3.1 20190703 (release) [gcc-8-branch revision 273027]
Using
-std=c++14
(ISO C++14)Using nlohmann/json release 3.7.3
The text was updated successfully, but these errors were encountered: