Bug 102502 - C11: _Static_assert disallows const int operand in -O0 while allows it in higher -O
Summary: C11: _Static_assert disallows const int operand in -O0 while allows it in hig...
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-09-27 18:35 UTC by Fangrui Song
Modified: 2021-12-15 17:24 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2021-09-27 18:35:53 UTC
Under some circumstances,

  const size_t allocation_size = 32768;
  _Static_assert (allocation_size >= sizeof (struct dirent64), "allocation_size < sizeof (struct dirent64)");

-O0 and non -O0 have different behaviors whether the `const int` operand can be used in a constant expression (-O0: `error: expression in static assertion is not constant`).
This is different from a bug "fixed for GCC 8 by r8-4755".


git clone https://sourceware.org/git/glibc.git
cd glibc
mkdir -p out/gcc; cd out/gcc
../../configure --prefix=/tmp/glibc/gcc --disable-werror
make -j 20   # you can SIGINT after some needed files used below are generated

Comment out some lines to allow -O0 compiles:

--- i/include/libc-symbols.h
+++ w/include/libc-symbols.h
@@ -71,9 +71,9 @@
 #define _LIBC  1
 
 /* Some files must be compiled with optimization on.  */
-#if !defined __ASSEMBLER__ && !defined __OPTIMIZE__
-# error "glibc cannot be compiled without optimization"
-#endif
+//#if !defined __ASSEMBLER__ && !defined __OPTIMIZE__
+//# error "glibc cannot be compiled without optimization"
+//#endif
 
 /* -ffast-math cannot be applied to the C library, as it alters the ABI.
    Some test components that use -ffast-math are currently not part of



# My source dir is at $HOME/Dev/glibc . You may need to adjust.
a=(../sysdeps/unix/sysv/linux/dl-opendir.c -std=gnu11 -fgnu89-inline -g -Wall -Wwrite-strings -Wundef -fmerge-all-constants -frounding-math -fno-stack-protector -fno-common -Wstrict-prototypes -Wold-style-definition -fmath-errno -fPIC -fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0 -mno-mmx -ftls-model=initial-exec -I../include -I$HOME/Dev/glibc/out/gcc/elf -I$HOME/Dev/glibc/out/gcc -I../sysdeps/unix/sysv/linux/x86_64/64 -I../sysdeps/unix/sysv/linux/x86_64 -I../sysdeps/unix/sysv/linux/x86/include -I../sysdeps/unix/sysv/linux/x86 -I../sysdeps/x86/nptl -I../sysdeps/unix/sysv/linux/wordsize-64 -I../sysdeps/x86_64/nptl -I../sysdeps/unix/sysv/linux/include -I../sysdeps/unix/sysv/linux -I../sysdeps/nptl -I../sysdeps/pthread -I../sysdeps/gnu -I../sysdeps/unix/inet -I../sysdeps/unix/sysv -I../sysdeps/unix/x86_64 -I../sysdeps/unix -I../sysdeps/posix -I../sysdeps/x86_64/64 -I../sysdeps/x86_64/fpu/multiarch -I../sysdeps/x86_64/fpu -I../sysdeps/x86/fpu -I../sysdeps/x86_64/multiarch -I../sysdeps/x86_64 -I../sysdeps/x86/include -I../sysdeps/x86 -I../sysdeps/ieee754/float128 -I../sysdeps/ieee754/ldbl-96/include -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/wordsize-64 -I../sysdeps/ieee754 -I../sysdeps/generic -I.. -I../libio -I. -D_LIBC_REENTRANT -include $HOME/Dev/glibc/out/gcc/libc-modules.h -include ../include/libc-symbols.h -DPIC -DSHARED -DTOP_NAMESPACE=glibc -fsyntax-only)

cd $HOME/Dev/glibc/elf


% gcc-11 $=a -O2  # no diagnostic
% gcc-11 $=a -O1  # no diagnostic
% gcc-11 $=a -O0
In file included from ../include/features.h:488,
                 from ../posix/sys/types.h:25,
                 from ../include/sys/types.h:1,
                 from ../sysdeps/unix/sysv/linux/dirstream.h:21,
                 from ../include/dirent.h:3,
                 from ../sysdeps/unix/sysv/linux/opendir.c:18,
                 from ../sysdeps/unix/sysv/linux/dl-opendir.c:1:
../sysdeps/unix/sysv/linux/opendir.c: In function ‘__alloc_dir’:
../sysdeps/unix/sysv/linux/opendir.c:107:35: error: expression in static assertion is not constant
  107 |   _Static_assert (allocation_size >= sizeof (struct dirent64),
      |                   ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
../include/sys/cdefs.h:7:59: note: in definition of macro ‘_Static_assert’
    7 | # define _Static_assert(expr, diagnostic) _Static_assert (expr, diagnostic)
      |                                                           ^~~~


gcc-8, gcc-9, and gcc-10 from Debian testing have the same behavior.
Comment 1 Andrew Pinski 2021-09-27 18:41:34 UTC
Can you attach the preprocessed source?
Comment 2 Jakub Jelinek 2021-09-27 18:55:55 UTC
Why do you think it is a bug?
This is not valid C11 code, and as an extension gcc when optimizations enabled in some cases will accept in constant expressions even something that it doesn't have to.
With -pedantic-errors it is properly rejected at all optimization levels.
It is also rejected at file scope.
If you want to make it valid in C11, use enum { allocation_size = (size_t) 32768 };
instead.
const doesn't work in C the same as in C++...
Comment 3 Fangrui Song 2021-09-27 19:53:07 UTC
OK, Andrew asked me to file it :)
I just wanted to fix glibc and run away from the GCC inconsistency.

I know that
https://www.iso-9899.info/n1570.html#6.6 p10 says
"An implementation may accept other forms of constant expressions."

Accepting `const int` in C mode is an extension, but it seems odd to be inconsistent (-O0 and -O2 -Wpedantic reject it while -O2 allows it).


% cat reduce.i
const int __alloc_dir_allocation_size = 8;
void __alloc_dir() { _Static_assert(__alloc_dir_allocation_size, ""); }

% gcc reduce.i -c -std=c11 
reduce.i: In function ‘__alloc_dir’:
reduce.i:2:37: error: expression in static assertion is not constant
    2 | void __alloc_dir() { _Static_assert(__alloc_dir_allocation_size, ""); }
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
% gcc reduce.i -c -std=c11 -O1
% gcc reduce.i -c -std=c11 -O2
% gcc reduce.i -c -std=c11 -O2 -Wpedantic
reduce.i: In function ‘__alloc_dir’:
reduce.i:2:37: warning: expression in static assertion is not an integer constant expression [-Wpedantic]
    2 | void __alloc_dir() { _Static_assert(__alloc_dir_allocation_size, ""); }
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~


Clang just rejects it in all optimization levels.


% clang reduce.i -c -std=c11 -O0
reduce.i:2:37: error: static_assert expression is not an integral constant expression
void __alloc_dir() { _Static_assert(__alloc_dir_allocation_size, ""); }
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
% clang reduce.i -c -std=c11 -O1
reduce.i:2:37: error: static_assert expression is not an integral constant expression
void __alloc_dir() { _Static_assert(__alloc_dir_allocation_size, ""); }
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Comment 4 Andrew Pinski 2021-09-27 20:54:05 UTC
(In reply to Jakub Jelinek from comment #2)
> Why do you think it is a bug?

Because there were other bugs which were fixed where there was an inconsistency, PR 66618, and PR 71983 for an example. There are others.

Oh there is an inconsistency when the _Static_assert is not in a function vs inside a function.
Take:
static const int allocation_size = 32768;
_Static_assert (allocation_size, "");
void f(void) { _Static_assert(allocation_size, ""); }

The assert inside the function is accepted at -O1 but reject at -O0 while the one outside is always rejected.
Comment 5 Jakub Jelinek 2021-09-27 21:05:04 UTC
(In reply to Andrew Pinski from comment #4)
> (In reply to Jakub Jelinek from comment #2)
> > Why do you think it is a bug?
> 
> Because there were other bugs which were fixed where there was an
> inconsistency, PR 66618, and PR 71983 for an example. There are others.
> 
> Oh there is an inconsistency when the _Static_assert is not in a function vs
> inside a function.
> Take:
> static const int allocation_size = 32768;
> _Static_assert (allocation_size, "");
> void f(void) { _Static_assert(allocation_size, ""); }
> 
> The assert inside the function is accepted at -O1 but reject at -O0 while
> the one outside is always rejected.

But it is an intentional decision, to match the previous behavior in that area plus handle what was needed.