Skip to content

C++ extractor answers __has_builtin for builtins the emulated GCC does not have (__is_convertible_to) #23094

Open

Description

@ANegm-ETAS

Summary

CodeQL 2.27.4's C++ extractor answers __has_builtin(__is_convertible_to) with 1;
the compiler it emulates (GCC 11.4, and GCC 12.2 behind QNX q++) answers 0

codeql_extractor_usecase.zip

. libc++
guards std::is_convertible with exactly that test, so the extractor takes the
__is_convertible(T, U) builtin branch and then cannot parse it:

is_convertible.h:30: error: type name is not allowed
is_convertible.h:30: error: identifier "__is_convertible" is undefined

std::is_convertible becomes an error type and everything built on it collapses.
That is the root cause of the >1000 errors in #22514 (closed): _If<<error-constant>>
(conditional.h:36), _OrImpl<<error-constant>>, conjunction<…, is_convertible<…>> has no member "value", iterator_traits<…> has no member "iterator_category" and the
pair / optional / chrono::duration constructor failures were all cascades.
Correct behaviour: __has_builtin(__is_convertible_to) == 0 for a GCC mimic

Minimal reproduction (no QNX SDK, no non-standard headers)

has_builtin_probe.cpp, 4 code lines, attached. GCC accepts it silently, the
extractor does not:

#if __has_builtin(__is_convertible_to)
static_assert(sizeof(int) == 999, "HAS_IS_CONVERTIBLE_TO_BUILTIN");
#endif

int probe_x;
$ codeql/cpp/tools/linux64/extractor --mimic /usr/bin/g++ \
      -std=c++17 -c has_builtin_probe.cpp -o /tmp/p.o
"has_builtin_probe.cpp", line 15: error: static assertion failed with "HAS_IS_CONVERTIBLE_TO_BUILTIN"
"has_builtin_probe.cpp", line 15: note: the final comparison was 4 == 999

builtin_probe.cpp (12 code lines, attached) turns the same mismatch into the
type name is not allowed / identifier "__is_convertible" is undefined pair.

Impact (QNX SDP 8.0.0, q++ = GCC 12.2.0 + libc++ std::__2, CodeQL 2.27.4)

Bazel-driven extraction of 74 C++17 translation units:

Metric Value
Translation units with parse errors 73 / 74 (98.6 %)
Unique parse errors 1133
First error in every TU is_convertible.h:30: error: type name is not allowed
conjunction/disjunction<… is_convertible<…>> has no member "value" 330

trigger.min.cpp (3 lines, attached) reproduces this on stock libc++ headers: q++
compiles it, the extractor reports 6 errors; trigger.cpp (53 lines) reports 76.

It is not a single builtin

A bitmask of __has_builtin(...) over eight C++17 builtins — revealed through an
incomplete show<N> template — is 108 for GCC 11.4 and 237 for the extractor.
The differing bits are __is_convertible_to and __is_nothrow_assignable, both 0 → 1;
the latter is also evaluated wrongly: the extractor says
__is_nothrow_assignable(int, long) is false.

Why the usual -E + creduce recipe does not apply

-E resolves the feature test with the real compiler's answer, so the preprocessed TU
contains libc++'s portable __is_convertible_imp fallback and extracts cleanly:
trigger.i (68 013 lines, attached) yields 0 errors where the same TU extracted from
source yields 76. The disagreement exists only inside the extractor's own
preprocessor, hence source-level probes in the attachment.

Workaround

-D_LIBCPP_USE_IS_CONVERTIBLE_FALLBACK forces libc++'s portable is_convertible and
removes every diagnostic (76 → 0 here), with no semantic change.

Also: q++ cannot be used as a --mimic target

It fails the probe (Not a compiler; exiting. Reason: --version stdout was: — the QNX
driver prints its banner on stderr), and the probe runs with a stripped
environment, so the GCC frontend behind q++ aborts with
cc: The QNX_HOST/QNX_TARGET environment variables must be set. mimic-qnx-gxx.sh
works around both.

Attached bundle (codeql_extractor_usecase/)

File What it is
has_builtin_probe.cpp, .i 4-line SDK-free feature-test probe and its -E output
builtin_probe.cpp, .i 12-line probe producing the __is_convertible diagnostic
trigger.min.cpp 3-line reduction on real libc++ headers
trigger.cpp, trigger.i 53-line realistic TU (76 errors) and preprocessed form (0 errors)
run.sh PASS/FAIL driver, 11 checks, SKIPs SDK steps when no SDK is installed
mimic-qnx-gxx.sh, reduce.py --mimic wrapper and the reducer behind trigger.min.cpp
README.md, logs/ Full write-up and verbatim compiler/extractor output

Environment: CodeQL CLI 2.27.4; reproducer host Ubuntu 22.04 / g++ 11.4.0; original
case QNX SDP 8.0.0 with q++ (GCC 12.2.0 frontend) and libc++ std::__2.

Activity

  1. ANegm-ETAS commented on Nov 11, 2026

    @ANegm-ETAS
    Author
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions