Bug 69550 - Need a way to disable "flexible array member in an otherwise empty struct" error on GCC 6
Summary: Need a way to disable "flexible array member in an otherwise empty struct" er...
Status: RESOLVED WONTFIX
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-01-29 10:45 UTC by Milan Bouchet-Valat
Modified: 2017-05-05 09:39 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-01-29 00:00:00


Attachments
Test C++ program which compiles with GCC 5 but not with GCC 6 (99 bytes, text/plain)
2016-01-29 10:45 UTC, Milan Bouchet-Valat
Details
Test C++ program which compiles with GCC 5 but not with GCC 6 (101 bytes, text/plain)
2016-01-29 13:44 UTC, Milan Bouchet-Valat
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Milan Bouchet-Valat 2016-01-29 10:45:36 UTC
Created attachment 37514 [details]
Test C++ program which compiles with GCC 5 but not with GCC 6

GCC 6 has become stricter than GCC 5 as regards having two flexible array members in a struct with no other fields. In GCC 5, the attached test program used to compile fine. It only triggered a warning with -Wpedantic. In GCC 6, it triggers an error with all -std modes.

While this is arguably against the standard, the fact that this code was accepted before and not in GCC 6 is a problem when the public API of a library includes such a construct: the library cannot be built with GCC 6 without breaking the API. This is the case for Julia [1].

Would it be possible to provide a way to turn the error into a warning? For example, -std=gnu++11 could allow this, while -std=c++11 would still consider it as an error.



1: https://github.com/JuliaLang/julia/pull/14829
Comment 1 Marek Polacek 2016-01-29 10:59:00 UTC
CCing Martin.
Comment 2 Jonathan Wakely 2016-01-29 11:05:50 UTC
The code is nonsense, what's it even supposed to do?

It would be invalid in C (where flexible arrays are actually standard) because flexible arrays can only be the last member, *and* because apart from the flexible arrays it's an otherwise empty struct. It's useless, and only compiled by accident.

Allowing it with -fpermissive might make sense though, as that flag allows all kinds of terrible rubbish to compile.
Comment 3 Jonathan Wakely 2016-01-29 11:07:35 UTC
(In reply to Milan Bouchet-Valat from comment #0)
> Would it be possible to provide a way to turn the error into a warning? For
> example, -std=gnu++11 could allow this, while -std=c++11 would still
> consider it as an error.

There is no reason to sanction this as a supported GNU extension. If it's allowed it should only be via -fpermissive which means "yes I know my code is rubbish but I can't fix it".
Comment 4 Milan Bouchet-Valat 2016-01-29 11:49:24 UTC
Yes, -fpermissive is a better solution. The code at stake has been replaced in the master branch, but breaking API in stable releases isn't great.
Comment 5 Milan Bouchet-Valat 2016-01-29 12:50:08 UTC
Note this actually also happens with the C compiler (the attached example also illustrates this).
Comment 6 Marek Polacek 2016-01-29 12:54:53 UTC
(In reply to Milan Bouchet-Valat from comment #5)
> Note this actually also happens with the C compiler (the attached example
> also illustrates this).

That's the correct behavior.
Comment 7 H.J. Lu 2016-01-29 13:11:36 UTC
Also see PR 60336 for impact of empty class.
Comment 8 Milan Bouchet-Valat 2016-01-29 13:12:20 UTC
(In reply to Marek Polacek from comment #6)
> (In reply to Milan Bouchet-Valat from comment #5)
> > Note this actually also happens with the C compiler (the attached example
> > also illustrates this).
> 
> That's the correct behavior.

As I said, I don't deny it's the correct application of the standard, nor that it's a sane behavior. But the fact that this was accepted without even a warning by default in the last GCC release, and that no way to disable the error is offered in GCC 6 creates problems for existing code bases.
Comment 9 Marek Polacek 2016-01-29 13:15:34 UTC
(In reply to Milan Bouchet-Valat from comment #8)
> As I said, I don't deny it's the correct application of the standard, nor
> that it's a sane behavior. But the fact that this was accepted without even
> a warning by default in the last GCC release, and that no way to disable the
> error is offered in GCC 6 creates problems for existing code bases.

Note that this was only accepted by the C++ compiler; the C compiler always rejected such a code (going back to at least gcc 3.4).
Comment 10 Jonathan Wakely 2016-01-29 13:20:01 UTC
(In reply to Milan Bouchet-Valat from comment #5)
> Note this actually also happens with the C compiler (the attached example
> also illustrates this).

Which is a Good Thing.

It's also a Good Thing that the C++ compiler is now consistent.

GCC has improved. Much rejoicing.
Comment 11 Milan Bouchet-Valat 2016-01-29 13:31:18 UTC
(In reply to Marek Polacek from comment #9)
> Note that this was only accepted by the C++ compiler; the C compiler always
> rejected such a code (going back to at least gcc 3.4).

Indeed you're right. The example only compiles with gcc (both 5 and 6) after changing the first struct member to *fieldptr0[0].
Comment 12 Jonathan Wakely 2016-01-29 13:39:27 UTC
Apparently the case they actually care about in Julia is not what was posted here, which might be where the disagreement comes from. What they actually have is:

typedef struct mytype {
    struct mytype *fieldptr0[0];
    struct mytype *fieldptr[];
} mytype;

The C front-end *does* accept this, which uses the non-standard zero-length array extension *and* a flexible array member.
Comment 13 Jonathan Wakely 2016-01-29 13:40:43 UTC
So if the intention is for the C++ front-end to match the C front-end then this should be accepted (and there's no need to allow the original example even with -fpermissive).
Comment 14 Milan Bouchet-Valat 2016-01-29 13:44:02 UTC
Created attachment 37520 [details]
Test C++ program which compiles with GCC 5 but not with GCC 6

Yes, sorry, I was about to explain the actual use case. Looks like I oversimplified the test program, as I hadn't spotted the difference of behavior in gcc (as opposed to g++).

I've updated the test case to reflect this.
Comment 15 Martin Sebor 2016-01-29 17:07:34 UTC
I did try to match the C front end but there are a few cases where I made C++ slightly stricter based on Jason's input about the direction C++ is heading with respect to aliasing rules.  This is one of those cases (there's a test for it in the test suite).

In addition, besides maintaining the property that every complete type has a non-zero size, the C rationale for requiring structs containing a flexible array to have at least one other member is to store the size of the array alongside it.

As for the request to relax the stricter C++ rules with -fpermissive, while I defer to Jason and others, my inclination is not to unless it turns out that the use case of having just a zero-length array and a flexible array as the sole members is a common idiom.

Regarding the test case in the attachment, I'm not sure I understand the purpose of having two arrays that are essentially equivalent.  Flexible array members were introduced into the language as a replacement of zero-length arrays (to avoid what's known as the struct hack).  But if having two such arrays is nececcary for some reason, changing the flexible array member to a zero-length array should get around the error in an ABI/API compatible way.
Comment 16 Jonathan Wakely 2016-01-29 17:44:17 UTC
OK, given that using a zero-sized array for both members works I would say we probably don't need to keep this open.
Comment 17 Yichao Yu 2016-01-29 18:22:59 UTC
I didn't write that code originally but I think I know why it is written this way when trying to fix the compiler warning/errors.

What we want is basically,

```
struct _jl_value_t {
    struct _jl_value_t *fieldptr[];
};
```

It needs to be a flexible array rather than an zero-length array since it will cause a runtime error on OSX otherwise. (Ref https://github.com/JuliaLang/julia/pull/13845 I don't have a mac to check but I assume it is done by clang in certain debug mode).

However, this doesn't work since the struct mush have another (in priciple non-empty) member and that's why we added a zero length array member in the struct which is non-standard but seems to have worked around the compiler warning on GCC < 6.

If this change is made intentionally in C++ mode, I'm fine with keeping it as is given we've already fixed it on our master and it's easy enough (at least for us) to work around this on our stable branch without breaking any existng setup. I'm not sure if other projects will have the same problem though.
Comment 18 Milan Bouchet-Valat 2016-02-06 15:19:23 UTC
FWIW, Debian has identified a few packages failing to build with the "flexible array member in otherwise empty struct" error under GCC 6:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=812023
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=812024
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=812026

Not sure whether these affect public API or not.
Comment 19 Milan Bouchet-Valat 2016-02-21 13:37:10 UTC
So what's your decision regarding this? Knowing it would help deciding how to handle it in Julia.
Comment 20 Martin Sebor 2016-02-21 20:51:23 UTC
Thank you for the references to the other bugs.  Having reviewed them, they each seem like a straightforward misuse of flexible array members in C++.  Since each case is rejected in C mode, it is deliberately also rejected in C++ mode

The bugs need to be fixed by either adding anothr member to the structs containing the flexible array, or by changing it to a zero-length array instead.  I would expect implementing one of these two kinds of solutions to be possible without breaking binary compatibility.

I'm resolving this request as WONTFIX.  If other problems crop up where simple fixes aren't possible please either open a new bug or reopen this one.