Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

documentation for behavior of extensions is sorely lacking; -std= documentation should indicate it does not turn off extensions #39319

Open Quuxplusone opened 5 years ago

Quuxplusone commented 5 years ago
Bugzilla Link PR40347
Status CONFIRMED
Importance P enhancement
Reported by Andi McClure (andi.m.mcclure@gmail.com)
Reported on 2019-01-16 21:31:53 -0800
Last modified on 2019-01-17 14:50:41 -0800
Version trunk
Hardware PC All
CC blitzrakete@gmail.com, dgregor@apple.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
Fixed by commit(s)
Attachments CMakeLists.txt (152 bytes, text/plain)
Blocks
Blocked by
See also
Created attachment 21344
BUILD SCRIPT FOR MAIN.CPP

REPRO STEPS

Here's a simple program.

//////////

#include "stdio.h"

#define LEFT 0
#define RIGHT 1

const char *test[] = {
    [LEFT] = "left",
    [RIGHT] = "right",
};

int main() {
    printf("%s\n", test[LEFT]);
    return 0;
}

//////////

I save this as main.cpp. I build this using the attached CMakeLists.txt, which
happens to produce the invocation line:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-std=c++11 -o CMakeFiles/clangtest.dir/main.cpp.o -c
/Users/mcc/work/h/clangbug/main.cpp

EXPECTED BEHAVIOR

This program should not compile. The [LEFT]= [RIGHT]= stuff is an example of
the "designated initializer" feature. This is a feature of C99, but I
understand it is not a feature of C++11. I do not find it in the N3242 draft
(section 8.5, "Initializers") and several people I trust assure me that it is
not a C++11 feature.

The fact I requested -std=c++11 implies that the C++11 standard is what I
wanted, not some significantly amended standard.

OBSERVED BEHAVIOR

The program works and prints "left".

If I add to the command line -Werror=c99-extensions, or add to the CMakeLists
set (CMAKE_CXX_FLAGS -Werror=c99-extensions), it fails with the helpful error
message "designated initializers are a C99 feature".

COMMENTS / "WHY I CARE"

The context of this bug report is that I have a program which must work cross
platform. In particular it must compile in standard OS X Clang, in standard
Android Native Development Kit Clang, and in standard Microsoft Visual Studio.
I do not always have access to my Visual Studio workstation, and so it is a
great imposition if when I sit down at my Visual Studio workstation I discover
only then that the program does not compile. The best way I know to ensure that
it will compile in Visual Studio is to target the standard, which Microsoft is
much better now at following than they used to be. I try to get my compilers to
target the standard by placing this in my CMakeLists.txt:

set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_EXTENSIONS OFF)

The way CMake interprets my request for EXTENSIONS OFF when targeting clang is
to insert -std=c++11 when invoking clang. If EXTENSIONS is ON or is not set, it
passes -std=gnu++11 . In other words, at least one major open source project
jumped to the same conclusion I did in my "EXPECTED BEHAVIOR", that std=c++11
means the unadorned standard and this is in fact the reasoning for separating
c++11 and gnu++11.

Today I needed to do a quick test of my project on Windows. I checked out and
built. It did not work. MSVC failed (correctly) on the designated initializer
line. That had snuck in at some point and I did not know it was not valid C++.
I had to waste time at a very inconvenient moment trying to understand why it
wasn't compiling. Ironically, I think? that MSVC in other modes *will* support
C99 features in C++, but for this build I had requested the C++11 standard so
apparently that's what it applied. -std=c++11 had not succeeded at the task I
wanted it for.

THE THIRD STAGE OF GRIEF IS BARGAINING

I don't know what kinds of considerations resulted in -std=C++11 mode including
C99 extensions. Maybe this is as-intended. (I'd personally prefer Clang allow
C99 features in C++, *if* I wasn't on a project where portability is
important.) However *even if* this is as-intended, this is *still* a bug
insofar as it is a documentation bug. If I look at

https://clang.llvm.org/docs/ClangCommandLineReference.html

all it says re: -std is
"-std=<arg>, --std=<arg>, --std <arg>
Language standard to compile for"
`man clang` on OS X says the same.

There is a separate page,
https://clang.llvm.org/cxx_status.html
which discusses C++ compliance status. It flatly says "Clang 3.3 and later
implement all of the ISO C++ 2011 standard." and gives *no* indication of a
major divergence like C99 extensions. (Given the level of detail on this page,
I would call such an omission actively misleading.)

The important thing to me is things should be predictable. I should be able to
predict what my builds will do based on the documentation.

I would expect that the -std= documentation would tell me what the options for -
std are, or how to look up what they are.

If -std=c++11 means something other than the "obvious" meaning (compliant
c++11) then the documentation should explain what that "something other" is. If
there is some specific set of flags that gets me "actually the c++11 standard",
the explanation of -std should document what those are.

The current situation is bad because
(1) I could not predict selecting c++11 would give me C++11 + C99
(2) Apparently, the CMake project could not predict this either
(3) Now that I know -std=C++11 is modified, I have no way of knowing *how much*-
- I could place -Werror=c99-extensions but I do not know if there are other
significant extensions also
(4) Since I don't truly know how to request "C++11, no extensions" I cannot go
to CMake and file a bug on *them* telling them to add -Werror=c99-extensions in
EXTENSIONS OFF mode
(5) An average user with less knowledge of standards politics than me would
probably not be able to figure out why XCode and MSVC are behaving differently
and would probably not have been able to find -Werror=c99-extensions on their
own.

CONFIGURATION

clang -v prints
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
It's from XCode. A Google search suggests this is equivalent to LLVM 4.0. My
test machine is running OS X 10.13.2.

I marked this bug as "trunk" because I tested with "godbolt.org" and I got the
same results as locally with both "x86-64 clang 7.0.0" and "x86-64 clang trunk".

My cmake is
cmake version 3.10.3
I think it's from Homebrew.

For comparison, my Visual Studio is 15.0 (which I think is VS2017) on Windows
10.
Quuxplusone commented 5 years ago

Attached CMakeLists.txt (152 bytes, text/plain): BUILD SCRIPT FOR MAIN.CPP

Quuxplusone commented 5 years ago

I filed a related bug on libc++ https://bugs.llvm.org/show_bug.cgi?id=40349

Quuxplusone commented 5 years ago
Clang has a number of extensions that are enabled by default, some for GCC
compatibility, some for compatibility with commonly-used code, and some merely
because we don't want to pedantically reject code where the intent is obvious
(especially for use of later-standards-mode features in earlier standards
modes). Most of those generate warnings by default, which is sufficient to meet
the standard's requirements for conformance ("shall issue at least one
diagnostic message").

You can request errors for all such extensions with the -pedantic-errors flag.

(The above is all true for GCC and ICC as well.)

> The way CMake interprets my request for EXTENSIONS OFF when targeting clang
is to insert -std=c++11

That is a CMake bug. EXTENSIONS OFF should pass -pedantic-errors (to turn off
extensions) in addition to a -std= flag, to all compilers with a GCC-compatible
driver interface.

> this is *still* a bug insofar as it is a documentation bug

Agreed. Our documentation here is very much lacking.
Quuxplusone commented 5 years ago
GCC documents this behavior here:

https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#index-std-1
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-pedantic-1

(As a general rule, Clang's GCC-compatible driver attempts to follow GCC's
behavior. But that is no excuse for our documentation not covering this.)
Quuxplusone commented 5 years ago
Thanks. I do intend to file a bug with CMake and I will refer your statements
in this bug when I do so… first though I want to test MSVC a little more
because I'm discovering they also appear to accept *some* C99 extensions in
C++11 mode, just not all of them. I have not yet located the documentation
explaining why D:

Can you confirm two things?

1. If I pass -pedantic-errors then -Werror=c99-extensions is not needed? -
pedantic-errors implies -Werror=c99-extensions, yes?

2. There are certain compiler-specific extensions which are "expected
extensions", that is, rather than being new language features per se they are
designated areas for conveying compiler-specific semantics. I am specifically
here thinking of __attribute__ and #pragma. Will using -pedantic-errors cut off
these features in Clang? (Looking at the description of -pedantic-errors in
https://clang.llvm.org/docs/UsersManual.html it appears the answer is "no", but
that sections seems to only specifically address C.)

One more thought. The -pedantic-errors section in UsersManual.html mentions
some C macros which are defined certain ways so that #ifdef et al can detect
features being on or off. It would be great if the current clang settings wrt
extensions (c99 extensions, all extensions, etc) were similarly detectable
using macro checks in C++ also. And of course it would be great if any such
macros were documented (if they weren't already).
Quuxplusone commented 5 years ago
> I want to test MSVC a little more because I'm discovering they also
> appear to accept *some* C99 extensions in C++11 mode

I believe the option corresponding to -pedantic-errors in MSVC is /permissive-
(https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=vs-2017)

> 1. If I pass -pedantic-errors then -Werror=c99-extensions is not needed?
> -pedantic-errors implies -Werror=c99-extensions, yes?

Yes.

> 2. Will using -pedantic-errors cut off these features in Clang?

No. Features hidden behind reserved identifiers and #pragma are unaffected (so,
for instance, you can still use "_Complex double" in C++ under -pedantic-
errors, etc).

> It would be great if the current clang settings wrt extensions (c99
extensions,
> all extensions, etc) were similarly detectable using macro checks in C++ also.

Some of them are, but many aren't. (For example, __has_extension(X) for X in
{c_alignas, c_alignof, c_atomic, c_generic_selections, c_static_assert,
c_thread_local} can be used to detect support for those C extensions in earlier
C dialects and in C++, and those respond appropriately to -pedantic-errors.)

Those extensions for which we provide such feature-test mechanisms are
documented here: https://clang.llvm.org/docs/LanguageExtensions.html#checks-for-
standard-language-features