Skip to content

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

Merged
merged 1 commit into from
Dec 3, 2018
Merged

Conversation

miyuki
Copy link
Contributor

@miyuki miyuki commented Nov 22, 2018

Description

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 does not
    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

[x] Fix
[ ] Refactor
[ ] Target update
[ ] Functionality change
[ ] Docs update
[ ] Test update
[ ] Breaking change

#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
Copy link
Contributor

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.

Copy link
Contributor

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.

@0xc0170 0xc0170 requested a review from a team November 22, 2018 17:14
@@ -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};
Copy link
Contributor

@kjbracey kjbracey Nov 23, 2018

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.

Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor

@kjbracey kjbracey Nov 26, 2018

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 enums 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 #ifdefs, 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).

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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.)

@kjbracey
Copy link
Contributor

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?

@miyuki
Copy link
Contributor Author

miyuki commented Nov 23, 2018

I have updated the stdalign part. AC 6.12 will provide <stdalign.h> (I have committed it to the development branch today).

@0xc0170
Copy link
Contributor

0xc0170 commented Nov 23, 2018

Thanks @miyuki for fixing

Copy link
Contributor

@kjbracey kjbracey left a 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.
@kjbracey
Copy link
Contributor

@artokin, @JarkkoPaso - these fixes will need to be sent back to original repos, so please review.

@0xc0170
Copy link
Contributor

0xc0170 commented Nov 28, 2018

@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?

@kjbracey
Copy link
Contributor

@artokin and I are fine with merging here and propogating back. @JarkkoPaso?

@JarkkoPaso
Copy link

I'm ok with merging.

@cmonr
Copy link
Contributor

cmonr commented Dec 1, 2018

CI started

@mbed-ci
Copy link

mbed-ci commented Dec 1, 2018

Test run: SUCCESS

Summary: 4 of 4 test jobs passed
Build number : 1
Build artifacts
Build logs

@0xc0170 0xc0170 merged commit c62f654 into ARMmbed:master Dec 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants