Files
git/config.mak.dev
Patrick Steinhardt 8d386f51bc build: tolerate use of _Generic from glibc 2.43 with Clang
When building with `make DEVELOPER=1` we explicitly pass "-std=gnu99" to
the compiler so that we don't start leaning on features exposed by more
recent versions of the C standard. Unfortunately though, glibc 2.43
started to use type-generic expressions. This works alright with GCC,
but when compiling with Clang this leads to errors:

  $ make DEVELOPER=1 CC=clang
  CC daemon.o
  In file included from daemon.c:3:
  ./git-compat-util.h:344:11: error: '_Generic' is a C11 extension [-Werror,-Wc11-extensions]
    344 |         return !!strchr(path, '/');
        |                  ^
  /usr/include/string.h:265:3: note: expanded from macro 'strchr'
    265 |   __glibc_const_generic (S, const char *, strchr (S, C))
        |   ^
  /usr/include/x86_64-linux-gnu/sys/cdefs.h:838:3: note: expanded from macro '__glibc_const_generic'
    838 |   _Generic (0 ? (PTR) : (void *) 1,                     \
        |   ^

In theory, the `__glibc_const_generic` macro does have feature gating:

  #if !defined __cplusplus \
      && (__GNUC_PREREQ (4, 9) \
          || __glibc_has_extension (c_generic_selections) \
          || (!defined __GNUC__ && defined __STDC_VERSION__ \
              && __STDC_VERSION__ >= 201112L))
  # define __HAVE_GENERIC_SELECTION 1
  #else
  # define __HAVE_GENERIC_SELECTION 0
  #endif

But this feature gating isn't effective because `_has_extension()` will
always evaluate to true as C generics _are_ available as a language
extension to GNU C99 when using Clang. This would have been different if
`_has_feature()` was used instead, in which case it would have properly
evaluated to `false`.

Unfortunately, there is no easy way for us to work around the warning.
We cannot define `__HAVE_GENERIC_SELECTION` ourselves as that would lead
to a redefinition, and given that the conditions are or'd together we
cannot disable any of those, either.

Instead, work around the issue by not using -std=gnu99 with Clang when
using the Makefile and by disabling warnings about C11 extensions when
using Meson. This isn't ideal, but we at least retain the ability to
detect the (mis-)use of features from newer standards with GCC.

An alternative to this might be to simply bump the required C standard
to C11, which is 15 years old by now and should have support on most
platforms out there. But some more esoteric platforms may not have it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2026-05-24 09:31:32 +00:00

119 lines
3.9 KiB
Plaintext

ifndef COMPILER_FEATURES
COMPILER_FEATURES := $(shell ./tools/detect-compiler $(CC))
endif
ifeq ($(filter no-error,$(DEVOPTS)),)
DEVELOPER_CFLAGS += -Werror
SPARSE_FLAGS += -Wsparse-error
endif
DEVELOPER_CFLAGS += -Wall
ifeq ($(filter no-pedantic,$(DEVOPTS)),)
DEVELOPER_CFLAGS += -pedantic
ifneq ($(or $(filter gcc5,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),)
DEVELOPER_CFLAGS += -Wpedantic
ifneq ($(filter gcc10,$(COMPILER_FEATURES)),)
ifeq ($(uname_S),MINGW)
DEVELOPER_CFLAGS += -Wno-pedantic-ms-format
endif
endif
endif
endif
ifneq ($(uname_S),FreeBSD)
ifneq ($(filter gcc6,$(COMPILER_FEATURES)),)
ifndef USE_MIMALLOC
DEVELOPER_CFLAGS += -std=gnu99
endif
endif
else
# FreeBSD cannot limit to C99 because its system headers unconditionally
# rely on C11 features.
#
# Clang cannot limit to C99 when using glibc 2.43 because its system headers
# depend on the _Generic C11 feature. This works with GCC though.
endif
DEVELOPER_CFLAGS += -Wdeclaration-after-statement
DEVELOPER_CFLAGS += -Wformat-security
DEVELOPER_CFLAGS += -Wold-style-definition
DEVELOPER_CFLAGS += -Woverflow
DEVELOPER_CFLAGS += -Wpointer-arith
DEVELOPER_CFLAGS += -Wstrict-prototypes
DEVELOPER_CFLAGS += -Wunused
DEVELOPER_CFLAGS += -Wvla
DEVELOPER_CFLAGS += -Wwrite-strings
DEVELOPER_CFLAGS += -fno-common
DEVELOPER_CFLAGS += -Wunreachable-code
ifneq ($(filter clang9,$(COMPILER_FEATURES)),)
DEVELOPER_CFLAGS += -Wcomma
endif
ifneq ($(filter clang4,$(COMPILER_FEATURES)),)
DEVELOPER_CFLAGS += -Wtautological-constant-out-of-range-compare
endif
ifneq ($(or $(filter gcc6,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),)
DEVELOPER_CFLAGS += -Wextra
# if a function is public, there should be a prototype and the right
# header file should be included. If not, it should be static.
DEVELOPER_CFLAGS += -Wmissing-prototypes
ifeq ($(filter extra-all,$(DEVOPTS)),)
# These are disabled because we have these all over the place.
DEVELOPER_CFLAGS += -Wno-empty-body
DEVELOPER_CFLAGS += -Wno-missing-field-initializers
endif
endif
# uninitialized warnings on gcc 4.9.2 in xdiff/xdiffi.c and config.c
# not worth fixing since newer compilers correctly stop complaining
#
# Likewise, gcc older than 4.9 complains about initializing a
# struct-within-a-struct using just "{ 0 }"
ifneq ($(filter gcc4,$(COMPILER_FEATURES)),)
ifeq ($(filter gcc5,$(COMPILER_FEATURES)),)
DEVELOPER_CFLAGS += -Wno-uninitialized
DEVELOPER_CFLAGS += -Wno-missing-braces
endif
endif
# Old versions of clang complain about initializing a
# struct-within-a-struct using just "{0}" rather than "{{0}}". This
# error is considered a false-positive and not worth fixing, because
# new clang versions do not, so just disable it.
#
# The "bug" was fixed in upstream clang 9.
#
# Complicating this is that versions of clang released by Apple have
# their own version numbers (associated with the corresponding version
# of XCode) unrelated to the official clang version numbers.
#
# The bug was fixed in Apple clang 12.
#
ifneq ($(filter clang1,$(COMPILER_FEATURES)),) # if we are using clang
ifeq ($(uname_S),Darwin) # if we are on darwin
ifeq ($(filter clang12,$(COMPILER_FEATURES)),) # if version < 12
DEVELOPER_CFLAGS += -Wno-missing-braces
endif
else # not darwin
ifeq ($(filter clang9,$(COMPILER_FEATURES)),) # if version < 9
DEVELOPER_CFLAGS += -Wno-missing-braces
endif
endif
endif
# glibc 2.43 headers unconditionally use _Generic even when we ask the
# compiler to stick to -std=gnu99 and unlike GCC, clang lacks a
# workaround to squelch warnings from system headers.
ifneq ($(filter clang1,$(COMPILER_FEATURES)),) # if we are using clang
DEVELOPER_CFLAGS += -Wno-c11-extensions
endif
# https://bugzilla.redhat.com/show_bug.cgi?id=2075786
ifneq ($(filter gcc12,$(COMPILER_FEATURES)),)
DEVELOPER_CFLAGS += -Wno-error=stringop-overread
endif
GIT_TEST_PERL_FATAL_WARNINGS = YesPlease