Enabling strong enum extensions under C

Hi,

Swift has generally been well-received, and there is active development
occurring to support it well on other targets, including ports to Android and
FreeBSD. As part of this work, it has become apparent that certain (objc)
extensions would be extremely useful to have available when working with swift.

One such feature in particular is CF_ENUM/CF_OPTIONS support. This is currently
only enabled under Objective-C compilation. This extension provides strong
enums similar to C++11’s enum class. In order to improve Swift’s
interoperability, it would be useful to enable this in C as well.

To explain the utility more concretely, enabling this extension allows for
cleaner cross-platform code in Swift. Having differences in the C variant means
that the code needs to be conditionalised via ‘#if’ checks, making it difficult
to follow. Most swift code is written against a C variant which enables strong
enumerations by default, and this results in a difference in the language
constructs based on the environment. Most documentation and example code are
written assuming this as well and it can be very difficult to diagnose why code
works in one environment but not the other. This disparity makes interfacing
with libraries a challenging endeavour for developers.

The question is what is the best option for enabling this extension on platforms
where we have non-clang compatibility involved (e.g. Linux). Should we just be
aggressive and introduce additional compiler specific extensions without
considerations for -std, vend a custom standard, or introduce a feature flag
to control these additional extensions that are useful for Swift.

There are pros and cons to each option, and this email is intended to open a
dialogue around which option would be the best long term for clang and the
language in general.

Thanks!

Hi,

Swift has generally been well-received, and there is active development
occurring to support it well on other targets, including ports to Android and
FreeBSD. As part of this work, it has become apparent that certain (objc)
extensions would be extremely useful to have available when working with swift.

One such feature in particular is CF_ENUM/CF_OPTIONS support. This is currently
only enabled under Objective-C compilation. This extension provides strong
enums similar to C++11's enum class. In order to improve Swift's
interoperability, it would be useful to enable this in C as well.

Hi Saleem,

The most conservative (and thus, probably the right answer, given that this is C) approach is to introduce a new attribute to clang to model this. Throwing __attribute__((swift_option_set)) on the enum (or whatever) could trigger the existing Swift importer logic to handle this.

The aggressive approach would be to make several proposals to the C committee to move the C model forward, but that seems unlikely to happen.

-Chris

Hi, Saleem. I think you’ve conflated two features here:

  • ObjC’s implementation of C++11’s “enums with fixed underlying types” feature.
  • An as-of-yet-undesigned annotation (attribute?) on enums that describes if they are really exclusive enums (like CF_ENUM) or bitsets (CF_OPTIONS) or just random constants.

I think these should be discussed separately, and I think you’re more interested in the former right now. Is that correct?

If so, this certainly seems reasonable to me. Like many other things added to the language, we can treat this as a feature of Objective-C and C++ >= 11, and an extension in C and C++ < 11. (This is the technical difference between __has_feature and __has_extension.) I think the Objective-C implementation of this is close to what would eventually go into the C standard, so treating it as a general language extension makes sense to me.

Jordan

Personally, I’d like if -std=c11 would give you C11 without extensions. I know that’s currently not the case and that GNU and clang extensions are enabled by default, but I really like the model we’re using in clang-cl: -std=c++11 gives you C++11-per-spec, and if you pass -fms-extensions and -fms-compatiblity, you get the Microsoft extensions. And if you want, -Wmicrosoft will warn you every time you use one that isn’t in a system header. I wish that we had a similar setup for GNU extensions – doing this has been discussed on this list a few times; maybe it’ll happen one day. Maybe the Swift extension setup could be similar? -fswift-extensions to opt in (your third proposal), and some warning group to warn about each use of such an extension.

Nico

Personally, I’d like if -std=c11 would give you C11 without extensions. I know that’s currently not the case and that GNU and clang extensions are enabled by default, but I really like the model we’re using in clang-cl: -std=c++11 gives you C++11-per-spec, and if you pass -fms-extensions and -fms-compatiblity, you get the Microsoft extensions. And if you want, -Wmicrosoft will warn you every time you use one that isn’t in a system header. I wish that we had a similar setup for GNU extensions – doing this has been discussed on this list a few times; maybe it’ll happen one day. Maybe the Swift extension setup could be similar? -fswift-extensions to opt in (your third proposal), and some warning group to warn about each use of such an extension.

We certainly can add -fswift-extensions, but it’s a level of divergence I’d like to avoid.

Regardless, enums with a fixed underlying type are an extremely useful extension in C, because it makes it a whole lot easier to keep an ABI stable. For example, we’ve seen a whole lot of “enumeration” types written like this:

enum {
ColorRed,
ColorGreen,
ColorBlue
};
typedef int32_t ColorType;

because the authors wanted to keep ColorType 32-bit regardless of the size of “int”. Note how the typedef and enumeration type are disjoint. Doing the obvious thing creates a type that varies with the size of int:

typedef enum ColorType {
ColorRed,
ColorGreen,
ColorBlue
} ColorType;

Fixed underlying types address this problem with syntax that is unambiguous in C and the obvious semantics:

typedef enum ColorType : int32_t {
ColorRed,
ColorGreen,
ColorBlue
} ColorType;

Frankly, I think standard C should adopt C++11’s enumerations with fixed underlying type, and Clang can help nudge C forward in this regard.

  • Doug

Personally, I’d like if -std=c11 would give you C11 without extensions. I know that’s currently not the case and that GNU and clang extensions are enabled by default, but I really like the model we’re using in clang-cl: -std=c++11 gives you C++11-per-spec, and if you pass -fms-extensions and -fms-compatiblity, you get the Microsoft extensions. And if you want, -Wmicrosoft will warn you every time you use one that isn’t in a system header. I wish that we had a similar setup for GNU extensions – doing this has been discussed on this list a few times; maybe it’ll happen one day. Maybe the Swift extension setup could be similar? -fswift-extensions to opt in (your third proposal), and some warning group to warn about each use of such an extension.

We certainly can add -fswift-extensions, but it’s a level of divergence I’d like to avoid.

Avoiding the divergence is ideal, however, this would break the meaning of -std=c11 or -std=gnu11. That was one of the other options that is available: we could vend a LLVM standard by default which would be GNU + extensions that we want to push for standardization. This would allow us to avoid the -fswift-extensions option, but retain the functionality.

Regardless, enums with a fixed underlying type are an extremely useful extension in C, because it makes it a whole lot easier to keep an ABI stable. For example, we’ve seen a whole lot of “enumeration” types written like this:

enum {
ColorRed,
ColorGreen,
ColorBlue
};
typedef int32_t ColorType;

because the authors wanted to keep ColorType 32-bit regardless of the size of “int”. Note how the typedef and enumeration type are disjoint. Doing the obvious thing creates a type that varies with the size of int:

typedef enum ColorType {
ColorRed,
ColorGreen,
ColorBlue
} ColorType;

Fixed underlying types address this problem with syntax that is unambiguous in C and the obvious semantics:

typedef enum ColorType : int32_t {
ColorRed,
ColorGreen,
ColorBlue
} ColorType;

I don’t think there has been any argument made that this is not a useful extension.

Frankly, I think standard C should adopt C++11’s enumerations with fixed underlying type, and Clang can help nudge C forward in this regard.

As Chris mentioned, this is likely to take a long time.

I think that there is a middle ground where we enable the behavior by default but provide a mechanism to disable. It may be sufficient to keep both sides happy.

Is this the only C extension you need for swift? What about -fblocks?

If it’s just typed enums and you don’t think it’ll become more over time, it probably doesn’t matter much all either way. If you think you’ll need more features over time, having some global toggle for this seems nice. It could default to on for -std=gnuX (if you use this, you don’t mind extensions) and to off for -std=cX (if you use this, you probably want to use the language as standardized), or something like that.

Is this the only C extension you need for swift? What about -fblocks?

That’s my concern as well. I can see that it may become convenient to enable more features over time, and having a global toggle for that seems nicer.

If it’s just typed enums and you don’t think it’ll become more over time, it probably doesn’t matter much all either way. If you think you’ll need more features over time, having some global toggle for this seems nice. It could default to on for -std=gnuX (if you use this, you don’t mind extensions) and to off for -std=cX (if you use this, you probably want to use the language as standardized), or something like that.

Though, by doing that, you wouldn’t be able to use the same code on GCC even with the same set of extensions. Explicitly having the flag to control that could prevent that. Adding a flag to enable features rather than disable them seems easier to manage.

Is this the only C extension you need for swift? What about -fblocks?

That's my concern as well. I can see that it may become convenient to
enable more features over time, and having a global toggle for that seems
nicer.

If it's just typed enums and you don't think it'll become more over time,
it probably doesn't matter much all either way. If you think you'll need
more features over time, having some global toggle for this seems nice. It
could default to on for -std=gnuX (if you use this, you don't mind
extensions) and to off for -std=cX (if you use this, you probably want to
use the language as standardized), or something like that.

Though, by doing that, you wouldn't be able to use the same code on GCC
even with the same set of extensions. Explicitly having the flag to
control that could prevent that. Adding a flag to enable features rather
than disable them seems easier to manage.

That's a good point.

Is this the only C extension you need for swift?

I believe that it’s the only non-attribute extension not covered by an existing flag.

What about -fblocks?

This already has a flag, which Swift’s Clang importer can set if it’s important. I haven’t heard a ton of demand for blocks outside of Darwin clients.

If it’s just typed enums and you don’t think it’ll become more over time, it probably doesn’t matter much all either way. If you think you’ll need more features over time, having some global toggle for this seems nice. It could default to on for -std=gnuX (if you use this, you don’t mind extensions) and to off for -std=cX (if you use this, you probably want to use the language as standardized), or something like that.

Swift’s Clang importer can certainly use -std=gnu, and keep fixed underlying types out of -std=c.

  • Doug

I do want to mention that Clang has plenty of other Clang-only extensions that we added to -std=gnu. We haven’t thought about adding a -std=clang flag before.

This isn’t a Swift feature; it’s an Objective-C feature that Swift makes use of.

Jordan

Is this the only C extension you need for swift?

I believe that it’s the only non-attribute extension not covered by an
existing flag.

What about -fblocks?

This already has a flag, which Swift’s Clang importer can set if it’s
important. I haven’t heard a ton of demand for blocks outside of Darwin
clients.

If it's just typed enums and you don't think it'll become more over time, it
probably doesn't matter much all either way. If you think you'll need more
features over time, having some global toggle for this seems nice. It could
default to on for -std=gnuX (if you use this, you don't mind extensions) and
to off for -std=cX (if you use this, you probably want to use the language
as standardized), or something like that.

Swift’s Clang importer can certainly use -std=gnu<whatever>, and keep fixed
underlying types out of -std=c<X>.

I do want to mention that Clang has plenty of other Clang-only extensions
that we added to -std=gnu<whatever>.

That sounds like a bug. The difference between -std=cX and -std=gnuX
should be exactly the same as enabling a (hypothetical)
-fgnu-extensions (or perhaps -fgnu-compatibility) flag -- that is, it
should only enable GNU extensions. Do you have an example?

Is this the only C extension you need for swift?

I believe that it’s the only non-attribute extension not covered by an
existing flag.

What about -fblocks?

This already has a flag, which Swift’s Clang importer can set if it’s
important. I haven’t heard a ton of demand for blocks outside of Darwin
clients.

If it’s just typed enums and you don’t think it’ll become more over time, it
probably doesn’t matter much all either way. If you think you’ll need more
features over time, having some global toggle for this seems nice. It could
default to on for -std=gnuX (if you use this, you don’t mind extensions) and
to off for -std=cX (if you use this, you probably want to use the language
as standardized), or something like that.

Swift’s Clang importer can certainly use -std=gnu, and keep fixed
underlying types out of -std=c.

I do want to mention that Clang has plenty of other Clang-only extensions
that we added to -std=gnu.

That sounds like a bug. The difference between -std=cX and -std=gnuX
should be exactly the same as enabling a (hypothetical)
-fgnu-extensions (or perhaps -fgnu-compatibility) flag – that is, it
should only enable GNU extensions. Do you have an example?

I take it back; it seems we merely have Clang extensions that we added without any flags, other than -Wpedantic. The closest thing is that we accept any constant-foldable integer as an array size in GNU mode, and our constant folding logic probably doesn’t exactly match GCC’s.

Although this seems wrong:

if (!LangOpts.GNUMode && !LangOpts.MSVCCompat)

Builder.defineMacro(“STRICT_ANSI”);

Given that, I’m not sure why this would be different from any other Clang extension that was added without a flag.

Jordan

Is this the only C extension you need for swift?

I believe that it’s the only non-attribute extension not covered by an
existing flag.

What about -fblocks?

This already has a flag, which Swift’s Clang importer can set if it’s
important. I haven’t heard a ton of demand for blocks outside of Darwin
clients.

If it's just typed enums and you don't think it'll become more over time,
it
probably doesn't matter much all either way. If you think you'll need more
features over time, having some global toggle for this seems nice. It could
default to on for -std=gnuX (if you use this, you don't mind extensions)
and
to off for -std=cX (if you use this, you probably want to use the language
as standardized), or something like that.

Swift’s Clang importer can certainly use -std=gnu<whatever>, and keep fixed
underlying types out of -std=c<X>.

I do want to mention that Clang has plenty of other Clang-only extensions
that we added to -std=gnu<whatever>.

That sounds like a bug. The difference between -std=cX and -std=gnuX
should be exactly the same as enabling a (hypothetical)
-fgnu-extensions (or perhaps -fgnu-compatibility) flag -- that is, it
should only enable GNU extensions. Do you have an example?

I take it back; it seems we merely have Clang extensions that we added
without *any* flags, other than -Wpedantic.

Actually here's one where even -Wpedantic won't coax a warning out of clang:

Sean:~/tmp % cat testpedantic.c
__attribute__((enable_if(1, "foo")))
void bar() {
}

Sean:~/tmp % clang -c testpedantic.c -std=c11 -Wpedantic -pedantic
Sean:~/tmp % clang -c testpedantic.c -std=c11 -Wpedantic
Sean:~/tmp % clang -c testpedantic.c -std=c99 -Wpedantic
Sean:~/tmp %

-- Sean Silva

The closest thing is that we accept any constant-foldable integer as an

Is this the only C extension you need for swift?

I believe that it’s the only non-attribute extension not covered by an
existing flag.

What about -fblocks?

This already has a flag, which Swift’s Clang importer can set if it’s
important. I haven’t heard a ton of demand for blocks outside of Darwin
clients.

If it's just typed enums and you don't think it'll become more over time,
it
probably doesn't matter much all either way. If you think you'll need more
features over time, having some global toggle for this seems nice. It could
default to on for -std=gnuX (if you use this, you don't mind extensions)
and
to off for -std=cX (if you use this, you probably want to use the language
as standardized), or something like that.

Swift’s Clang importer can certainly use -std=gnu<whatever>, and keep fixed
underlying types out of -std=c<X>.

I do want to mention that Clang has plenty of other Clang-only extensions
that we added to -std=gnu<whatever>.

That sounds like a bug. The difference between -std=cX and -std=gnuX
should be exactly the same as enabling a (hypothetical)
-fgnu-extensions (or perhaps -fgnu-compatibility) flag -- that is, it
should only enable GNU extensions. Do you have an example?

I take it back; it seems we merely have Clang extensions that we added
without *any* flags, other than -Wpedantic. The closest thing is that we
accept any constant-foldable integer as an array size in GNU mode, and our
constant folding logic probably doesn't exactly match GCC's.

I think that those should really be considered bugs.

Honestly, given that the addition of `-fgnu-extensions` has been discussed
multiple times, I think that it is reasonable to try to provide a mechanism
for helping users write portable code (yes, clang is a great compiler and
hopefully fits everyone's needs, but that doesn't mean that people won't
use any other compilers). Rather than silently introducing non-standard
behavior we could provide a means to identify those and allow users to
determine if they wish to use that.

That is not to say we could not enable the extensions by default, but
merely that we should have a way to disable the extensions and at the very
least indicate that they are being used. Doing so may help push certain
features into the standard as Doug was suggesting.

Speaking with OS developer hat, it is not practical to disable all
extensions like the protected versions of keywords or attributes.

Joerg

I have the same kind of dilemma - I really like having a "strictly conforming" option because I love Standards, but realistically I need them to be supplemented by a relaxed mode that permits extensions.

What I think would be the right thing for Clang, would be for '-std=XXX' to enforce the ISO definition of XXX, but to be able to supplement it with an additional option or options that enabled the extensions or relaxed the ISO rules (warnings of divergence are still good). Normally when I use '-std=XXX', I also find I have to use at least ' -U__STRICT_ANSI__' because the extended or non-Standard behaviour is what I often want; and sometimes other additional options. But having '-std=XXX' mean exactly the ISO definition is really useful, and cool.

Ironically, having '-std=XXX' be really strict about ISO compliance is almost certainly the wrong thing for my code; for example it means enabling exceptions which are simply too expensive for embedded; but I would still like to tell the compiler to enforce strict ISO conformance rules - unless I have supplemented it with options to relax particular constraints. Sometimes we use '-std=XXX' to select a dialect (e.g. C++11 versus C++14), but then have to supplement it by a bunch of other options that tune it to our actual non-Standard needs. But I still need warnings and error messages, they tell me where I need to be very specific about what and why I am doing something that strays outside the ISO interpretation.

An alternative would to be to add something like '-fstrict-iso' to make '-std=XXX' be strict, but my own feeling is that strict should be the default, and relaxed should be the deliberately selected alternative.

  MartinO

I have the same kind of dilemma - I really like having a "strictly
conforming" option because I love Standards, but realistically I need them
to be supplemented by a relaxed mode that permits extensions.

What I think would be the right thing for Clang, would be for '-std=XXX'
to enforce the ISO definition of XXX, but to be able to supplement it with
an additional option or options that enabled the extensions or relaxed the
ISO rules (warnings of divergence are still good). Normally when I use
'-std=XXX', I also find I have to use at least ' -U__STRICT_ANSI__' because
the extended or non-Standard behaviour is what I often want; and sometimes
other additional options. But having '-std=XXX' mean exactly the ISO
definition is really useful, and cool.

Ironically, having '-std=XXX' be really strict about ISO compliance is
almost certainly the wrong thing for my code; for example it means enabling
exceptions which are simply too expensive for embedded; but I would still
like to tell the compiler to enforce strict ISO conformance rules - unless
I have supplemented it with options to relax particular constraints.
Sometimes we use '-std=XXX' to select a dialect (e.g. C++11 versus C++14),
but then have to supplement it by a bunch of other options that tune it to
our actual non-Standard needs. But I still need warnings and error
messages, they tell me where I need to be very specific about what and why
I am doing something that strays outside the ISO interpretation.

An alternative would to be to add something like '-fstrict-iso' to make
'-std=XXX' be strict, but my own feeling is that strict should be the
default, and relaxed should be the deliberately selected alternative.

It seems that there is some interest in keeping the default be standards
conforming. It would be nice to get a consensus on this issue so that we
can move forward.

I have the same kind of dilemma - I really like having a "strictly
conforming" option because I love Standards, but realistically I need them
to be supplemented by a relaxed mode that permits extensions.

What I think would be the right thing for Clang, would be for '-std=XXX'
to enforce the ISO definition of XXX, but to be able to supplement it with
an additional option or options that enabled the extensions or relaxed the
ISO rules (warnings of divergence are still good). Normally when I use
'-std=XXX', I also find I have to use at least ' -U__STRICT_ANSI__' because
the extended or non-Standard behaviour is what I often want; and sometimes
other additional options. But having '-std=XXX' mean exactly the ISO
definition is really useful, and cool.

Ironically, having '-std=XXX' be really strict about ISO compliance is
almost certainly the wrong thing for my code; for example it means enabling
exceptions which are simply too expensive for embedded; but I would still
like to tell the compiler to enforce strict ISO conformance rules - unless I
have supplemented it with options to relax particular constraints.
Sometimes we use '-std=XXX' to select a dialect (e.g. C++11 versus C++14),
but then have to supplement it by a bunch of other options that tune it to
our actual non-Standard needs. But I still need warnings and error
messages, they tell me where I need to be very specific about what and why I
am doing something that strays outside the ISO interpretation.

An alternative would to be to add something like '-fstrict-iso' to make
'-std=XXX' be strict, but my own feeling is that strict should be the
default, and relaxed should be the deliberately selected alternative.

It seems that there is some interest in keeping the default be standards
conforming. It would be nice to get a consensus on this issue so that we
can move forward.

I would be very happy with us adding -fgnu-compatibility, and making
-std=gnuX be a synonym for -std=cX -fgnu-compatibility. This would
just cover the non-conforming GNU extensions (in particular, the GNU
keywords), in the same way that -fms-compatibility covers only the
non-conforming MS behavior.

That would leave us with a collection of GNU extensions (and Clang
extensions and Embarcadero extensions and probably others) that are
enabled with no explicit opt-out flag (such as __attribute__, folding
of non-constant array bounds). Some of the GNU extensions are at this
point Clang extensions as well (we have our own __attribute__s that
use GNU syntax), some of them are essential for the correct
functioning of system headers or for the compilation of widespread
code patterns, and some of them are things we could reasonably hide
behind a "GNU extensions" flag (etc). Unpicking the differences seems
like a significant challenge -- there's no point adding a flag for
these things that causes (in practice) all non-trivial compilations to
fail -- and we already have -pedantic-errors for cases where there is
a desire for errors on code that uses such an extension (we may miss
some extension diagnostics today; those are easy bugs to fix). I think
what we need here is for someone to come up with a proposal for a good
end state here.

There's a separate question of what the default -std= value should be,
for each language. Right now, we use -std=gnu11 for C and -std=gnu++98
for C++, although we should aim to bump the latter to -std=gnu++14 for
Clang 3.9. Changing these from -std=gnuX to -std=cX seems likely to
break a fair amount of real code, so we should be cautious about that.

>>
>> I have the same kind of dilemma - I really like having a "strictly
>> conforming" option because I love Standards, but realistically I need
them
>> to be supplemented by a relaxed mode that permits extensions.
>>
>> What I think would be the right thing for Clang, would be for '-std=XXX'
>> to enforce the ISO definition of XXX, but to be able to supplement it
with
>> an additional option or options that enabled the extensions or relaxed
the
>> ISO rules (warnings of divergence are still good). Normally when I use
>> '-std=XXX', I also find I have to use at least ' -U__STRICT_ANSI__'
because
>> the extended or non-Standard behaviour is what I often want; and
sometimes
>> other additional options. But having '-std=XXX' mean exactly the ISO
>> definition is really useful, and cool.
>>
>> Ironically, having '-std=XXX' be really strict about ISO compliance is
>> almost certainly the wrong thing for my code; for example it means
enabling
>> exceptions which are simply too expensive for embedded; but I would
still
>> like to tell the compiler to enforce strict ISO conformance rules -
unless I
>> have supplemented it with options to relax particular constraints.
>> Sometimes we use '-std=XXX' to select a dialect (e.g. C++11 versus
C++14),
>> but then have to supplement it by a bunch of other options that tune it
to
>> our actual non-Standard needs. But I still need warnings and error
>> messages, they tell me where I need to be very specific about what and
why I
>> am doing something that strays outside the ISO interpretation.
>>
>> An alternative would to be to add something like '-fstrict-iso' to make
>> '-std=XXX' be strict, but my own feeling is that strict should be the
>> default, and relaxed should be the deliberately selected alternative.
>
>
> It seems that there is some interest in keeping the default be standards
> conforming. It would be nice to get a consensus on this issue so that we
> can move forward.

I would be very happy with us adding -fgnu-compatibility, and making
-std=gnuX be a synonym for -std=cX -fgnu-compatibility. This would
just cover the non-conforming GNU extensions (in particular, the GNU
keywords), in the same way that -fms-compatibility covers only the
non-conforming MS behavior.

This sounds like a great idea to me.

That would leave us with a collection of GNU extensions (and Clang
extensions and Embarcadero extensions and probably others) that are
enabled with no explicit opt-out flag (such as __attribute__, folding
of non-constant array bounds). Some of the GNU extensions are at this
point Clang extensions as well (we have our own __attribute__s that
use GNU syntax), some of them are essential for the correct
functioning of system headers or for the compilation of widespread
code patterns, and some of them are things we could reasonably hide
behind a "GNU extensions" flag (etc). Unpicking the differences seems
like a significant challenge -- there's no point adding a flag for
these things that causes (in practice) all non-trivial compilations to
fail -- and we already have -pedantic-errors for cases where there is
a desire for errors on code that uses such an extension (we may miss
some extension diagnostics today; those are easy bugs to fix). I think
what we need here is for someone to come up with a proposal for a good
end state here.

I think that another option is having an option that is enabled by default
to enable these extensions to permit users to force a strict compilation
mode.

There's a separate question of what the default -std= value should be,

for each language. Right now, we use -std=gnu11 for C and -std=gnu++98
for C++, although we should aim to bump the latter to -std=gnu++14 for
Clang 3.9. Changing these from -std=gnuX to -std=cX seems likely to
break a fair amount of real code, so we should be cautious about that.

Sure, but I don't think that the changes being discussed here really impact
our choice of defaults outside of what the mapping of flags would be.