PaulStoffregen/Wire

GCC 6 compile errors

FrankBoesing opened this issue · 6 comments

Using ARM GCC 6 / Q2 , i get the following errors:
`
"C:\Arduino\hardware\teensy/../tools/arm6/bin/arm-none-eabi-g++" -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -fno-exceptions -felide-constructors -std=gnu++14 -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=140 -DARDUINO=10804 -DF_CPU=240000000 -DUSB_RAWHID -DLAYOUT_US_ENGLISH "@f:\arduino_build_3190/sketch/defs.h" "-IC:\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Arduino\hardware\teensy\avr\libraries\Audio" "-IC:\Arduino\hardware\teensy\avr\libraries\SPI" "-IC:\Arduino\hardware\teensy\avr\libraries\SD" "-IC:\Arduino\hardware\teensy\avr\libraries\SerialFlash" "-IC:\Arduino\hardware\teensy\avr\libraries\Wire" "-IC:\Arduino\hardware\teensy\avr\libraries\Wire\utility" "C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp" -o "f:\arduino_build_3190\libraries\Wire\WireKinetis.cpp.o"
C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:803:54: error: reinterpret_cast from integer to pointer

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:50:

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                              ~~~  

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:803:54:

constexpr uintptr_t i2c0_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C0));

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:51: note: in definition of macro 'MAKE_CONST'

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                               ^

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:808:54: error: reinterpret_cast from integer to pointer

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:50:

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                              ~~~  

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:808:54:

constexpr uintptr_t i2c1_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C1));

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:51: note: in definition of macro 'MAKE_CONST'

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                               ^

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:813:54: error: reinterpret_cast from integer to pointer

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:50:

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                              ~~~  

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:813:54:

constexpr uintptr_t i2c2_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C2));

C:\Arduino\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:800:51: note: in definition of macro 'MAKE_CONST'

#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))

                                              ^

`

I think constexpr uintptr_t i2c0_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C1.A1));
would work (no compile errors on Gcc5 + GCC6) - but I could not test with I2C hardware.

Might be this change in gcc 4.9.2.

Unlikely. It works without any errors on gcc 5.4.

@PaulStoffregen: Why is this macro used in the first place? It seems to return ((x)), no matter if respected x can be folded or not.

Looks like that old hack to circumvent the constexpr reinterpret_cast limitation does not work anymore in gcc and clang.

As a workaround I added KINETIS_I2CX_ADDR as a macros that only contains the address to kinetis.h and used them inside KINETIS_I2CX and without the MAKE_CONST(...) inside the Wire library:

--- core/kinetis.h	2018-06-20 20:47:18.000000000 +0200
+++ core/kinetis.h	2018-07-02 18:57:59.911936300 +0200
@@ -4566,10 +4566,14 @@
 	volatile uint8_t	SLTH;
 	volatile uint8_t	SLTL;
 } KINETIS_I2C_t;
-#define KINETIS_I2C0		(*(KINETIS_I2C_t *)0x40066000)
-#define KINETIS_I2C1		(*(KINETIS_I2C_t *)0x40067000)
-#define KINETIS_I2C2		(*(KINETIS_I2C_t *)0x400E6000)
-#define KINETIS_I2C3		(*(KINETIS_I2C_t *)0x400E7000)
+#define KINETIS_I2C0_ADDR	0x40066000
+#define KINETIS_I2C1_ADDR	0x40067000
+#define KINETIS_I2C2_ADDR	0x400E6000
+#define KINETIS_I2C3_ADDR	0x400E7000
+#define KINETIS_I2C0		(*(KINETIS_I2C_t *) KINETIS_I2C0_ADDR)
+#define KINETIS_I2C1		(*(KINETIS_I2C_t *) KINETIS_I2C1_ADDR)
+#define KINETIS_I2C2		(*(KINETIS_I2C_t *) KINETIS_I2C2_ADDR)
+#define KINETIS_I2C3		(*(KINETIS_I2C_t *) KINETIS_I2C3_ADDR)
 #define I2C0_A1			(KINETIS_I2C0.A1)		// I2C Address Register 1
 #define I2C0_F			(KINETIS_I2C0.F)		// I2C Frequency Divider register
 #define I2C_F_DIV20			((uint8_t)0x00)
--- src/WireKinetis.cpp	2018-07-02 18:51:19.323864755 +0200
+++ src/WireKinetis.cpp	2018-07-02 18:50:23.742853593 +0200
@@ -874,31 +871,23 @@
 };
 #endif
 
-// Helper to transform a non-constant expression of the form
-// &(*(KINETIS_I2C_t *)0x40066000)
-// into a compile time constant.
-#define MAKE_CONST(x) (__builtin_constant_p(x) ? (x) : (x))
-
 #ifdef WIRE_IMPLEMENT_WIRE
-constexpr uintptr_t i2c0_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C0));
+constexpr uintptr_t i2c0_addr = uintptr_t(KINETIS_I2C0_ADDR);
 TwoWire Wire(i2c0_addr, TwoWire::i2c0_hardware);
 void i2c0_isr(void) { Wire.isr(); }
 #endif
 #ifdef WIRE_IMPLEMENT_WIRE1
-constexpr uintptr_t i2c1_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C1));
+constexpr uintptr_t i2c1_addr = uintptr_t(KINETIS_I2C1_ADDR);
 TwoWire Wire1(i2c1_addr, TwoWire::i2c1_hardware);
 void i2c1_isr(void) { Wire1.isr(); }
 #endif
 #ifdef WIRE_IMPLEMENT_WIRE2
-constexpr uintptr_t i2c2_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C2));
+constexpr uintptr_t i2c2_addr = uintptr_t(KINETIS_I2C2_ADDR);
 TwoWire Wire2(i2c2_addr, TwoWire::i2c2_hardware);
 void i2c2_isr(void) { Wire2.isr(); }
 #endif
 #ifdef WIRE_IMPLEMENT_WIRE3
-constexpr uintptr_t i2c3_addr = uintptr_t(MAKE_CONST(&KINETIS_I2C3));
+constexpr uintptr_t i2c3_addr = uintptr_t(KINETIS_I2C3_ADDR);
 TwoWire Wire3(i2c3_addr, TwoWire::i2c3_hardware);
 void i2c3_isr(void) { Wire3.isr(); }
 #endif

You could probably drop the surrounding uintptr_t(...) as well.

What was the reason to use this construct in the first place? For something as trivial as this, a hack like that just makes the code harder to read and maintain.