From 3f3b503feed54c87aef40f45f3f35f505cb2e6da Mon Sep 17 00:00:00 2001 From: flink Date: Mon, 20 Jul 2026 21:16:49 -0400 Subject: [PATCH 1/2] Set matching CC alongside CXX in Linux CI matrix The Configure step only set CXX, so CMake's C compiler detection fell back to whatever the default happened to be on the runner, independent of which C++ compiler the matrix entry was actually testing (e.g. CXX=clang++-3.6 but CC left to detect GCC 11). Derive CC from the same matrix.cxx value the job already installs a matching compiler for. --- .github/workflows/linux.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 70260dd9..a301c6dd 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -174,6 +174,13 @@ jobs: sudo apt install locales-all cmake -E make_directory ${{runner.workspace}}/build + - name: Select matching C compiler + run: | + cc=${{matrix.cxx}} + cc=${cc/clang++/clang} + cc=${cc/g++/gcc} + echo "CC=$cc" >> "$GITHUB_ENV" + - name: Configure working-directory: ${{runner.workspace}}/build env: From 2cd3227b89bd491a341d28606ca52d6a1f170a42 Mon Sep 17 00:00:00 2001 From: hexonal Date: Wed, 22 Jul 2026 22:12:26 -0400 Subject: [PATCH 2/2] Skip c-test on clang++-3.6 due to pre-3.8 _Generic decay bug Now that CC correctly matches CXX for this job, test/c-test.c is compiled with real Clang 3.6.2 for the first time, which fails on string-literal arguments to fmt's C API macros ("too many arguments to function call, expected 0, have 1"). Root cause: fmt-c.h's FMT_MAKE_ARG uses a C11 _Generic dispatch with a 0-arg fmt_unsupported_type default. Whether the controlling expression of _Generic undergoes array-to-pointer decay was genuinely ambiguous in C11 wording (WG14 N1930); Clang treated it as an unconverted lvalue and did not decay arrays until the fix for LLVM PR16340 landed in November 2015 (clang 3.8). Clang 3.6.2 (Feb 2015) predates that fix, so a string literal like "foo" (type char[4]) never matches the char*/const char* cases and falls through to the default, which then gets called with an argument. Verified this is specific to old Clang, not a general fmt-c.h bug: - Compiled test/c-test.c against fmt-c.h with a modern Clang locally; it builds cleanly, confirming decay works correctly once PR16340 is fixed. - Confirmed no safe macro-level workaround exists: forcing decay uniformly (e.g. `(x) + 0` or `1 ? (x) : (x)`) triggers ordinary integer promotion for the small-integer cases (char, bool, short, etc.), silently routing them to the wrong fmt_from_* function on *all* compilers. A per-type-conditional wrapper isn't expressible without already knowing the type, i.e. without _Generic itself. Given this is a real, long-since-fixed upstream compiler bug in a 10-year-old Clang release, and no low-risk fix at the fmt-c.h level exists that doesn't risk changing dispatch behavior on every other compiler, skip just c-test (via ctest -E) for the clang++-3.6 job. The C++ test suite for that job is unaffected and still runs. The exclude value must be double-quoted when assigned from the templated expression, since GitHub Actions substitutes it inline and an unquoted assignment containing a space (e.g. exclude=-E ^c-test$) does not parse as a single shell assignment - it splits into a variable-scoped-to-command form that tries to execute a nonexistent '^c-test$' command, aborting the step under bash's default -e. Verified both branches (clang++-3.6 and every other matrix entry) by actually executing the resulting snippet with bash -eo pipefail. --- .github/workflows/linux.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index a301c6dd..5fa03bdc 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -206,6 +206,18 @@ jobs: - name: Test working-directory: ${{runner.workspace}}/build - run: ctest -C ${{matrix.build_type}} + # clang++-3.6 predates the fix for LLVM PR16340 (the controlling + # expression of _Generic wasn't decayed/qualifier-stripped before + # type matching, fixed upstream in clang 3.8). That makes + # FMT_MAKE_ARG's _Generic dispatch in fmt-c.h fail to match string + # literals (e.g. "foo", of type char[4]) against the char*/const + # char* cases, so they fall through to the 0-arg default case and + # the call is passed too many arguments. This is a real, long-fixed + # upstream compiler bug rather than a bug in fmt's macro, so only + # c-test is skipped here for this one job; see the discussion on + # https://github.com/fmtlib/fmt/pull/4863 for the full analysis. + run: | + exclude="${{ matrix.cxx == 'clang++-3.6' && '-E ^c-test$' || '' }}" + ctest -C ${{matrix.build_type}} $exclude env: CTEST_OUTPUT_ON_FAILURE: True