-
Notifications
You must be signed in to change notification settings - Fork 3k
Fix C++11 build with Arm Compiler 6 #8843
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
Conversation
#elif (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L) | ||
#elif defined __cplusplus && __cplusplus >= 201103L | ||
#define __alignas_is_defined 1 | ||
#elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This header is included mainly by C files - doesn't it still trip up? I guess you get away with it because you haven't switched ARMC6 to C11 mode yet. We will be doing that.
I'd rather have a solution that makes ARMC6 work fully - if we can't fix ARMC6, then detect it specifically and provide the stdalign.h substitute for both C and C++.
I'd be somewhat inclined to put that in mbed_retarget.h or something, as there will be other places wanting to use alignas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although actually this is a separate portability glue used outside Mbed OS too (mainly for C) so something still needs to be here.
@@ -374,7 +374,7 @@ static void rf_enable_gpio_interrupt(void) | |||
|
|||
static void rf_send_command(s2lp_commands_e command) | |||
{ | |||
const uint8_t tx[2] = {SPI_CMD, command}; | |||
const uint8_t tx[2] = {SPI_CMD, (uint8_t)command}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually a C++11 issue? As far as I'm aware, as long as all values of the enum
fit into the destination type, it's not viewed as a narrowing conversion for the initializer-list rules (8.5.4 - "from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type")
(But I do expect most compilers to utter a warning, in any mode, assigning any enum to an int). Er, no, other way around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, are the "values" of the enum for that clause the actual values listed in it, or the possible values of its underlying type?
Going through the rest of the standard, looking for references to "values" of enumerations, I think it's the latter.
Can't find anyone conclusively saying one way or the other out on the net.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kjbracey-arm command
is of type s2lp_commands_e
. The representation of s2lp_commands_e
is implementation defined . According to #8803, ARMC6 enums are 4 bytes now. It may explain the narrow conversion error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having reread C++11 7.2 several times, I can now buy the compiler's interpretation. Just need to be capable of distinguishing "enumerator values" (what you listed) from "values of the enumeration" (values of the underlying type). :) The standard uses both terms in 7.2...
In this case, it seems reasonable to interpret "values of the original type" as the latter, and those are basically implementation-defined, so you can't portably just stick enum
s into sub-int
integer initializers any more.
Now, I do hate casts, and the problem is better avoided in C++11 by changing the enumeration to actually specify it's supposed to be uint8_t
-based.
Can I suggest instead something like
#if defined __cplusplus && __cplusplus >= 201103
typedef enum : uint8_t {
#else
typedef enum {
#endif
...
} s2_lp_commands;
I do also hate #ifdef
s, but that can be stripped back down when we take C++11 as baseline.
(Conceivably you could have a define for enum_uint8_t
if you used that in multiple places).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can cause ODR violations if the user decides to define a struct with a field of type s2_lp_commands
and use it from both C and C++ code, say:
struct foo {
s2_lp_commands cmd;
char bar;
};
Now in C code bar
has offset 4 in struct foo
, whereas in C++ code it has offset 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True (although you'd probably get away with it after #8803).
You'd certainly have to be cautious about doing that sort of change in general.
In this case though it is an internal header used only from the C++ code, so C compatibility isn't an issue. (It's internalness isn't explicit, except for the Mbed OS 3-style code structure where it's living in source
rather than stm-s2lp-rf-driver
). I was anticipating the #ifdef
ultimately dropping so it was just always enum : uint8_t
, and not C compatible.
Don't know if we need to make the "this is C++" explicit, but we can certainly drop the spurious existing extern "C"
and my own's if defined __cplusplus
that suggest it might be C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Although this is a good example of how you might manage to create a C++03 versus C++11 library incompatibility. I don't think that's a concern in this limited context, but would certainly discourage me from doing similar anywhere more public.)
At least one of these is an ARM C 6 bug - do we have a channel open to get these fixed so workarounds don't have to live forever? |
I have updated the stdalign part. AC 6.12 will provide <stdalign.h> (I have committed it to the development branch today). |
Thanks @miyuki for fixing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding <stdalign.h>
and making the workaround specific.
On the other one, I feel strongly if the response to any rule tightening is adding a manual cast, then either the rule's broken or there must be a better code fix. In this case it seems there is a non-casting alternative, so I'd like to take it.
Currently there are two issues which prevent building Mbed OS with -std=gnu++11 when using Arm Compiler 6: * NanostackRfPhys2lp.cpp contains a narrowing conversion in a braced initializer list * ns_types.h includes <stdalign.h> which Arm Compiler 6 currently does not provide This patch fixes both issues. The first one is fixed by changing the underlying type of the corresponding enumeration when the code is compiled as C++11. The second issue is worked around by avoiding the use of <stdalign.h> header for Arm Compiler versions prior to 6.12.
@artokin, @JarkkoPaso - these fixes will need to be sent back to original repos, so please review. |
Shall this be do not merge or we accept them here and someone will propagate them to upstream repositories? |
@artokin and I are fine with merging here and propogating back. @JarkkoPaso? |
I'm ok with merging. |
CI started |
Test run: SUCCESSSummary: 4 of 4 test jobs passed |
Description
Currently there are two issues which prevent building Mbed OS with
-std=gnu++11 when using Arm Compiler 6:
initializer list
proivde
This patch fixes both issues. The first one is fixed by adding an
explicit cast. The second issue is worked around by avoiding the
<stdalign.h> header (alignas is a keyword in C++, so we don't actually
need to #include the header to use it).
Pull request type