Skip to content
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

Error: a reinterpret_cast is not a constant expression #36

Closed
marcovannoord opened this issue Jul 2, 2020 · 6 comments
Closed

Error: a reinterpret_cast is not a constant expression #36

marcovannoord opened this issue Jul 2, 2020 · 6 comments

Comments

@marcovannoord
Copy link

marcovannoord commented Jul 2, 2020

Hi,
I'm been changing from an ESP32/Arduino environment into an ESP32/esp-idf environment that has support for Arduino-code, and so far everything has been smooth, except for this library.
Somehow, the compiler trips over the following code:

#define DEFINE_FIELD(fieldname, value_t, obis, field_t, field_args...) \
  struct fieldname : field_t<fieldname, ##field_args> { \
    value_t fieldname; \
    bool fieldname ## _present = false; \
    static constexpr ObisId id = obis; \
    static constexpr char name_progmem[] DSMR_PROGMEM = #fieldname; \
    static constexpr const __FlashStringHelper *name = reinterpret_cast<const __FlashStringHelper*>(&name_progmem); \
    value_t& val() { return fieldname; } \
    bool& present() { return fieldname ## _present; } \
  }

at the reinterpret_cast<.... part it gives me this error:

.pio/libdeps/switch-1/Dsmr/src/dsmr/fields.h:185:56: error: a reinterpret_cast is not a constant expression
     static constexpr const __FlashStringHelper *name = reinterpret_cast<const __FlashStringHelper*>(&name_progmem); \
                                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.pio/libdeps/switch-1/Dsmr/src/dsmr/fields.h:231:1: note: in expansion of macro 'DEFINE_FIELD'
 DEFINE_FIELD(electricity_long_failures, uint32_t, ObisId(0, 0, 96, 7, 9), IntField, units::none);

What i've tried/checked

  • The build flags for the GCC compiler (C++11) for the Arduino environment and for the esp-idf environment are the same: gcc 8.2.0
  • the __FlashStringHelper is present, and is the same as before
  • The DEFINE_FIELD() functions where the DEFINE_FIELD macro is used, expand to the same code in both environments.

Could you give me any hints where i should look to solve this issue?

@matthijskooijman
Copy link
Owner

I was just running into this same error compiling DSMR on a regular PC instead of for Arduino. Good to know this also occurs with certain ESP cores.

The problem is probably that newer gcc versions (correctly) check the constness of expressions per the standard, where older versions would (incorrectly) allow this expression.

I tried the following patch, which seems to compile (but I haven't managed linking successfully, so I'm not sure if it actually works). If you try it, let me know if it works for you:

--- a/src/dsmr/fields.h
+++ b/src/dsmr/fields.h
@@ -176,13 +176,19 @@ const uint8_t WATER_MBUS_ID = 2;
 const uint8_t THERMAL_MBUS_ID = 3;
 const uint8_t SLAVE_MBUS_ID = 4;
 
+template <typename FieldT>
+struct NameConverter {
+  public:
+    operator const __FlashStringHelper*() const { return reinterpret_cast<const __FlashStringHelper*>(&FieldT::name_progmem); }
+};
+
 #define DEFINE_FIELD(fieldname, value_t, obis, field_t, field_args...) \
   struct fieldname : field_t<fieldname, ##field_args> { \
     value_t fieldname; \
     bool fieldname ## _present = false; \
     static constexpr ObisId id = obis; \
     static constexpr char name_progmem[] DSMR_PROGMEM = #fieldname; \
-    static constexpr const __FlashStringHelper *name = reinterpret_cast<const __FlashStringHelper*>(&name_progmem); \
+    static constexpr NameConverter<dsmr::fields::fieldname> name = {}; \
     value_t& val() { return fieldname; } \
     bool& present() { return fieldname ## _present; } \
   }

I'll probably continue work on this in the coming days, hopefully I can push a fix out soon.

@marcovannoord
Copy link
Author

Thanks for the quick response. I was already hitting my head at the wall, wondering what i did wrong with my build environment, but indeed good to hear that it's indeed intentionally failing.
I was already looking for compiler flags that would prevent it from checking the constexpr, but didn't find any yet.

For me, it still fails compiling, although it finds a conflicting declaration.

conflicting declaration 'constexpr const __FlashStringHelper* const dsmr::fields::identification::name'
 constexpr const __FlashStringHelper *identification::name;
                                                      ^~~~
In file included from .pio\libdeps\switch-1\Dsmr\src\dsmr\fields.cpp:31:
.pio\libdeps\switch-1\Dsmr\src\dsmr\fields.h:192:61: note: previous declaration as 'constexpr const dsmr::fields::NameConverter<dsmr::fields::identification> dsmr::fields::identification::name'
     static constexpr NameConverter<dsmr::fields::fieldname> name = {}; \
.pio\libdeps\switch-1\Dsmr\src\dsmr\fields.h:199:1: note: in expansion of macro 'DEFINE_FIELD'
 DEFINE_FIELD(identification, String, ObisId(255, 255, 255, 255, 255, 255), RawField);

@matthijskooijman
Copy link
Owner

Ah, I see I missed one. Try removing this line from fields.cpp:

constexpr const __FlashStringHelper *identification::name;

If that still breaks, maybe replace it with:

constexpr const dsmr::fields::NameConverter<dsmr::fields::identification> identification::name;

All of the other ::name lines need the same treatment.

@marcovannoord
Copy link
Author

Ah, that first one did the trick.
I will see if parsing works correctly, but at least compilation and linking works perfectly now.

marcovannoord added a commit to marcovannoord/arduino-dsmr that referenced this issue Jul 3, 2020
@marcovannoord
Copy link
Author

Yep, parsing seems to work perfectly with the patch you mentioned, plus removing the
constexpr const __FlashStringHelper *identification::name; line.

@matthijskooijman
Copy link
Owner

Awesome, thanks for confirming. I'll try to push out this change to the master branch in the coming days.

mrWheel added a commit to mrWheel/dsmr2Lib that referenced this issue May 6, 2021
DRN88 added a commit to DRN88/arduino-dsmr that referenced this issue Aug 14, 2021
DRN88 added a commit to DRN88/arduino-dsmr that referenced this issue Aug 14, 2021
hvegh pushed a commit to hvegh/arduino-dsmr that referenced this issue Jan 12, 2024
Newer gcc versions correctly enforce a C++ language limitation that
forbids using reinterpret_cast in constant expressions. This commit
works around this by replacing the `name` attribute with a `get_name()`
method that delays the cast until the time of use. Note that the method
will be inlined in practice, so there is no additional overhead.

For compatibility with existing code, the name attribute is replaced by
a NameConverter object that can be implicitly converted to `const
__FlashStringHelper *`. This should keep some code working, but not
everything (e.g. conversion to String can no longer be done implicitly,
see matthijskooijman#43).

In the future, the name attribute should probably be completely removed,
and replaced by a `name()` method (which is a bit more elegant than the
current `get_name()`)

This fixes matthijskooijman#36.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants