Bug 53091 - static initializer accepted by clang but not by gcc
Summary: static initializer accepted by clang but not by gcc
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.7.0
: P3 enhancement
Target Milestone: 8.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 53530 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-04-23 18:24 UTC by bugs
Modified: 2021-09-12 21:32 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work: 8.1.0
Known to fail: 7.5.0
Last reconfirmed: 2012-04-24 00:00:00


Attachments
Demo of problem (138 bytes, text/plain)
2012-04-23 18:25 UTC, bugs
Details

Note You need to log in before you can comment on or make changes to this bug.
Description bugs 2012-04-23 18:24:06 UTC
Works in Clang 2.9 and Clang 3.0

Succeeds in g++ FWIW.

$ gcc gcc_bug.c
gcc_bug.c:5: error: initializer element is not constant
Comment 1 bugs 2012-04-23 18:25:42 UTC
Created attachment 27224 [details]
Demo of problem
Comment 2 Jonathan Wakely 2012-04-23 18:38:29 UTC
The bug reporting guidelines ask for source code, not a URL.

Here's the code from the URL

#include <stdio.h>

const int SDL_HAT_UP = 0x01;
const int SDL_HAT_RIGHT = 0x02;
const int SDL_HAT_RIGHTUP = (SDL_HAT_RIGHT | SDL_HAT_UP);

int main(int argc, char **argv)
{
  printf("%x\n",SDL_HAT_RIGHTUP);
  return 0;
}

I think GCC is correct, the code is valid C++ but not valid C.

In C the initializer for a global variable must be a constant expression ("All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.") and (SDL_HAT_RIGHT | SDL_HAT_UP) is not a constant expression.

http://c-faq.com/ansi/constasconst.html

I believe Clang is allowed to accept the code because the C standard also says implementations may accept other forms of constant expression.
Comment 3 bugs 2012-04-23 18:59:59 UTC
Hey. I attached it as well. I didn't just provide a URL.

Anyway, I take it this is a "Won't Fix" ?

I guess it isn't the end of the world since we are targetting clang for llvm output anyway.
Although gcc would be nice-to-have.
I don't think he's big on making specialcase #defines in this converter.
Comment 4 Andreas Schwab 2012-04-23 19:20:25 UTC
Just use an enum.
Comment 5 Manuel López-Ibáñez 2012-04-23 19:25:26 UTC
(In reply to comment #3)
> Anyway, I take it this is a "Won't Fix" ?

Not sure why. If Clang is allowed by the C standard, then surely GCC is allowed as well. If the C++ FE has code to enable this, probably it can be reused in the C FE. GCC could accept it with a -Wpedantic warning.

In any case, like everything, it boils down to having someone make it happen, that is, providing a patch. I don't think any existing GCC developer will tackle this in the near future, otherwise it would have been done already.

But let's wait for Joseph opinion to confirm this.
Comment 6 bugs 2012-04-23 19:35:18 UTC
Oh, cool.
Probably going to replace w/ an enum, which does seem to work.
But it does make 0 sense to me that const int is forbidden, but enum is allowed...

http://publications.gbdirect.co.uk/c_book/chapter6/enums.html

Can rewrite both const int and enum, so I don't really see why enum is permitted but const int isn't, they both offer
about the same amount of safety.

I mean, might as well just force #define only. (please don't!)
Comment 7 Andrew Pinski 2012-04-23 19:39:52 UTC
>But it does make 0 sense to me that const int is forbidden, but enum is
allowed...


Why variables are not part of C's constant integer expressions.  enum values are not variables.
Comment 8 bugs 2012-04-23 19:57:37 UTC
In response to comment #7, I was referring to this portion of the linked document.
------
Not that you are likely to care, but the Standard states that enumeration types are of a type that is compatible with an implementation-defined one of the integral types. So what? For interest's sake here is an illustration:

enum ee{a,b,c}e_var, *ep;

The names a, b, and c all behave as if they were int constants when you use them;
------
So. you can rewrite enum values just as easily as you can a const int by taking a pointer to it.  And that site claims it behaves like a const int.
So, yeah, gotta say clang's behaviour seems more rational here.

Oh well. unc0rr might switch to enum in the interest of getting it working.  The conversion code is not quite as tidy, but no matter.

I'll let you guys hash it out.  At leas clang works for now.
Comment 9 Andreas Schwab 2012-04-23 20:36:10 UTC
enum constants are not objects, they don't have an address.
Comment 10 Jonathan Wakely 2012-04-23 20:50:21 UTC
(In reply to comment #3)
> Hey. I attached it as well. I didn't just provide a URL.

Yeah, sorry, I wrote my comment before you attached it.

(In reply to comment #6)
> Can rewrite both const int and enum, so I don't really see why enum is
> permitted but const int isn't, they both offer
> about the same amount of safety.

http://c-faq.com/ansi/constasconst.html

Take it up with the C committee, not GCC.


(In reply to comment #8)
> Not that you are likely to care, but the Standard states that enumeration types
> are of a type that is compatible with an implementation-defined one of the
> integral types.

Enumeration TYPES are compatible with integral TYPES.  But enumerators are constant, const-qualified variables are not constants.

> So. you can rewrite enum values just as easily as you can a const int by taking
> a pointer to it.  And that site claims it behaves like a const int.

The site's wrong.
Comment 11 bugs 2012-04-23 21:01:03 UTC
Yeah, I get the difference now.
Ok. Fair.
So, I guess clang is just taking the values of the const ints at the time the assignment occurs (0x01 and 0x02)
and assigning 0x03.  If RIGHT or UP were changed, RIGHTUP would not change.

Ok, what gcc is doing *does* make sense I 'spose :)
Comment 12 jsm-csl@polyomino.org.uk 2012-04-24 14:25:06 UTC
There is no requirement to accept this static initializer, but the code 
does try to be lax about constants in initializers (there is no 
requirement to reject it either) and fold them with c_fully_fold (see 
c-typeck.c:digest_init).  So it may make sense to look at why this laxity 
isn't causing this code to be accepted.
Comment 13 Manuel López-Ibáñez 2012-04-24 14:37:42 UTC
(In reply to comment #12)
> There is no requirement to accept this static initializer, but the code 
> does try to be lax about constants in initializers (there is no 
> requirement to reject it either) and fold them with c_fully_fold (see 
> c-typeck.c:digest_init).  So it may make sense to look at why this laxity 
> isn't causing this code to be accepted.

So confirmed.

bugs@m8y.org, I would recommend that if you are interested in this, take a more active role. First, by finding out where and why the C FE does not accept this code. Then posting the results of your investigation here.
Comment 14 bugs 2012-04-24 15:00:42 UTC
Heh. Thanks, but our current target is clang->llvm, I was just surprised that gcc did not accept it.
The codebase being converted by unc0rr's haskell-based tokeniser is pascal actually.
const
    SDL_HAT_UP        = $01;
    SDL_HAT_RIGHT     = $02;
    SDL_HAT_RIGHTUP   = SDL_HAT_RIGHT or SDL_HAT_UP;

Sooo, if you guys make it work in GCC, great, could be useful in the future, maybe for faster game builds on the desktop.
But not really a big priority.  Besides, unc0rr can probably change that to:
enum _consts 
{
SDL_HAT_UP = 0x01,
SDL_HAT_RIGHT = 0x02,
SDL_HAT_RIGHTUP = (SDL_HAT_RIGHT | SDL_HAT_UP)
};

To satisfy gcc's more delicate sensibilities.  :-p

Thanks for looking into it though, and I'll definitely watch the bug.
Comment 15 Andreas Schwab 2012-05-30 16:03:51 UTC
*** Bug 53530 has been marked as a duplicate of this bug. ***
Comment 16 Andrew Pinski 2021-09-12 21:28:07 UTC
Fixed for GCC 8 by r8-5025