Skip to content

Fix conditional inclusion of stdckdint.h#531

Open
darkain wants to merge 1 commit intoruby:masterfrom
darkain:patch-1
Open

Fix conditional inclusion of stdckdint.h#531
darkain wants to merge 1 commit intoruby:masterfrom
darkain:patch-1

Conversation

@darkain
Copy link
Copy Markdown

@darkain darkain commented Apr 20, 2026

Because __has_include is on a #elif line, it is still being evaluated by the pre-processor regardless of #if defined, even if not executed. It must exist on its own gated level inside of the #if block rather than at the same level as the #if block to function correctly.

This fixes a compilation error on a platform which doesn't have __has_include available.

Because `__has_include` is on a `#elif` line, it is still being evaluated by the pre-processor regardless of `#if defined`, even if not executed. It must exist on its own gated level inside of the `#if` block rather than at the same level as the `#if` block to function correctly.

This fixes a compilation error on a platform which doesn't have `__has_include` available.
@zenspider
Copy link
Copy Markdown
Member

cc @jhawthorn

@tompng
Copy link
Copy Markdown
Member

tompng commented Apr 28, 2026

This fixes a compilation error on a platform which doesn't have __has_include available.

Can you provide a platform or a code example that describe the compilation error?

The code below passes compile, so I think there's no compilation problem.

#define EXISTING_MACRO

#if defined(EXISTING_MACRO) || !defined(__nonexistent_preprocessor_operator)
#elif __nonexistent_preprocessor_operator(<stdckdint.h>)
# define EXISTING_MACRO 1
#endif

#if defined(NONEXISTENT_MACRO) || !defined(__nonexistent_preprocessor_operator)
#elif __nonexistent_preprocessor_operator(<stdckdint.h>)
# define NONEXISTENT_MACRO 1
#endif

My understanding is:

#if defined(HAVE_STDCKDINT_H) || !defined(__has_include)
  // Evaluated if HAVE_STDCKDINT_H already defined OR __has_include is not defined.
  // So elif condition is evaluated as negation of this: HAVE_STDCKDINT_H not defined AND __has_include defined
#elif __has_include(<stdckdint.h>)
# define HAVE_STDCKDINT_H 1
#endif

Let me know if my understanding is wrong.

#elif __has_include(<stdckdint.h>)
#if !defined(HAVE_STDCKDINT_H)
#if defined(__has_include)
#if __has_include(<stdckdint.h>)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original empty-if plus elif is not so readable, and there's a room improvement. But triple-nested-if is also not so good.

It's worth merging this as a refactoring even if there's no compilation problem in the original code.
#if cod1 && cond2 && cond3 may be better than tripple-nested-if and also better than empty-if plus elif. What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this file dtoa.c is a copy of https://github.com/ruby/ruby/blob/master/missing/dtoa.c. It was recently updated to the latest one.
I don't want to add a difference because updating the file might be difficult in the future.

@tompng
Copy link
Copy Markdown
Member

tompng commented Apr 28, 2026

This file dtoa.c is a copy of https://github.com/ruby/ruby/blob/master/missing/dtoa.c and it was recently updated to the latest one.
Please open a pull request to ruby/ruby after confirming if there is really a compilation error.

@tompng tompng closed this Apr 28, 2026
@darkain
Copy link
Copy Markdown
Author

darkain commented Apr 28, 2026

Rather than close this PR, how about we re-open this, get the upstream core Ruby file fixed and this one too? This is actively failing compilation on compilers that dont have the __has_include feature. The __has_include token is still being evaluated (even if not executed) because it isn't properly gated, which is why the nested #if statements are needed. If the token cannot be found in the syntax tree, the compiler will bail.

@darkain
Copy link
Copy Markdown
Author

darkain commented Apr 28, 2026

Installing Cookbook Gems:

Running handlers:
[2026-04-28T12:03:20-05:00] ERROR: Running exception handlers
Running handlers complete
[2026-04-28T12:03:20-05:00] ERROR: Exception handlers complete
ORC Infra Client failed. 0 resources updated in 33 seconds
[2026-04-28T12:03:21-05:00] FATAL: Stacktrace dumped to ...stacktrace.out
[2026-04-28T12:03:21-05:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2026-04-28T12:03:21-05:00] FATAL: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '5'
---- Begin output of ["bundle", "install"] ----
STDOUT: Fetching gem metadata from ..../api/gems/rubygems/.............
Resolving dependencies.......
Using base64 0.3.0
Using benchmark 0.5.0
Fetching bigdecimal 4.1.2
Installing bigdecimal 4.1.2 with native extensions
STDERR: Don't run Bundler as root. Bundler can ask for sudo if it is needed, and
installing your bundle as root will break this application for all non-root
users on this machine.
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

current directory:
.../gems/bigdecimal-4.1.2/ext/bigdecimal
checking for __builtin_clz()... yes
checking for __builtin_clzl()... yes
checking for __builtin_clzll()... yes
checking for float.h... yes
checking for math.h... yes
checking for stdbool.h... yes
checking for stdlib.h... yes
checking for x86intrin.h... yes
checking for _lzcnt_u32() in x86intrin.h... no
checking for _lzcnt_u64() in x86intrin.h... no
checking for intrin.h... no
checking for ruby/atomic.h... no
checking for ruby/internal/has/builtin.h... no
checking for ruby/internal/static_assert.h... no
checking for rb_complex_real() in ruby.h... yes
checking for rb_complex_imag() in ruby.h... yes
checking for rb_opts_exception_p() in ruby.h... yes
checking for rb_category_warn() in ruby.h... no
checking for RB_WARN_CATEGORY_DEPRECATED in ruby.h... no
checking for RUBY_TYPED_EMBEDDABLE in ruby.h... no
creating Makefile

current directory:
..../gems/bigdecimal-4.1.2/ext/bigdecimal
make "DESTDIR=" clean

current directory:
..../gems/bigdecimal-4.1.2/ext/bigdecimal
make "DESTDIR="
compiling bigdecimal.c
compiling missing.c
In file included from missing.c:28:0:
missing/dtoa.c:214:20: error: missing binary operator before token "("
 #elif __has_include(<stdckdint.h>)
                    ^
make: *** [missing.o] Error 1

make failed, exit code 2

Gem files will remain installed in
..../gems/bigdecimal-4.1.2 for inspection.
Results logged to
..../bigdecimal-4.1.2/gem_make.out

An error occurred while installing bigdecimal (4.1.2), and Bundler cannot
continue.
Make sure that `gem install bigdecimal -v '4.1.2' --source
'..../api/gems/rubygems/'` succeeds before bundling.

In Gemfile:
  activesupport was resolved to 7.1.6, which depends on
    bigdecimal
---- End output of ["bundle", "install"] ----
Ran ["bundle", "install"] returned 5

darkain added a commit to darkain/ruby that referenced this pull request Apr 28, 2026
The very thing the conditional for `__has_include` is trying to handle, is causing compilation to break.

This file was brought into the ruby/bigdecimal project, and is failing to compile on a platform which doesnt have `__has_include` support in the compiler.

Compile log can be found in this comment:
ruby/bigdecimal#531 (comment)
@tompng
Copy link
Copy Markdown
Member

tompng commented Apr 30, 2026

I see, so the cause is not only the existence of __has_include but how the compiler evaluates/parses elif condition part.
I'll wait for ruby/ruby's pull request.

By the way, I think it's worth adding a description/commit message to ruby/ruby#16802 that mention about elif difference rather than __has_include existence, and the environment, platform, compiler information.

@tompng tompng reopened this Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants