From 102a8e8786ab608959c0a37008600e198825b157 Mon Sep 17 00:00:00 2001 From: Austin Schuh Date: Tue, 28 Apr 2026 14:02:23 -0700 Subject: [PATCH] Add cuda_wrappers include feature for clang CUDA toolchains Clang ships cuda_wrappers/ shims under its resource directory (lib/clang//include/cuda_wrappers/) that #undef __noinline__ around libstdc++ headers, working around the CUDA host_defines.h macro conflict with libstdc++'s __attribute__((__noinline__)) (seen in bits/shared_ptr_base.h). Clang's CUDA driver already adds that directory automatically, but only as -internal-isystem. Clang merges all system-tier include groups in argument order, and -internal-isystem sorts after -cxx-isystem. So when the C++ standard library is injected explicitly via -nostdinc++ -cxx-isystem, the real bits/shared_ptr_base.h is found before clang's automatic cuda_wrappers entry; the wrapper never intercepts it via #include_next and the build fails on the __noinline__ clash. This worked before because clang was allowed to discover libstdc++ through its own GCC detection, which adds the stdlib as -internal-isystem *after* the cuda_wrappers entry the driver injects first, so the wrapper came first and fired automatically. Tightening the sandbox so clang no longer auto-detects the host toolchain (passing the stdlib via -cxx-isystem instead) reorders the stdlib ahead of the automatic wrapper and exposes the conflict. Fix it by detecting lib/clang//include in the cc_toolchain's built-in include directories and adding the cuda_wrappers subdir via -isystem to cuda_compile actions. -isystem (System group) sorts ahead of -cxx-isystem (CXXSystem), so the wrapper intercepts again. Clang dedups the now-redundant automatic -internal-isystem copy (RemoveDuplicates keeps the earlier occurrence), so this is safe even when the driver also adds it. --- cuda/private/toolchain_configs/clang.bzl | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/cuda/private/toolchain_configs/clang.bzl b/cuda/private/toolchain_configs/clang.bzl index aa85ce01..4ffb4c36 100644 --- a/cuda/private/toolchain_configs/clang.bzl +++ b/cuda/private/toolchain_configs/clang.bzl @@ -55,6 +55,17 @@ def _impl(ctx): env_paths, env_includes, _, libdevice_dir = collect_paths(ctx) env_entry_include = [env_entry("INCLUDE", path_separator.join(env_includes))] if env_includes else [] + # Clang ships `cuda_wrappers/` headers (e.g. bits/shared_ptr_base.h) that + # `#undef __noinline__` around libstdc++ headers, working around the + # CUDA `host_defines.h` macro conflict with libstdc++'s use of + # `__attribute__((__noinline__))`. They live under the clang resource + # directory at `lib/clang//include/cuda_wrappers/`. Detect that path + # from the cc_toolchain's built_in_include_directories. + cuda_wrappers_dirs = [] + for d in env_includes: + if "/lib/clang/" in d and d.endswith("/include"): + cuda_wrappers_dirs.append(d + "/cuda_wrappers") + clang_compile_env_feature = feature( name = "clang_compile_env", enabled = True, @@ -578,8 +589,38 @@ def _impl(ctx): cuda_compile_action, ] + cuda_wrappers_include_feature = feature( + name = "cuda_wrappers_include", + enabled = True, + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cuda_compile], + # Emit these as `-isystem` (not `-idirafter`) so the wrappers + # land ahead of the libstdc++ headers that a hermetic + # toolchain injects via `-cxx-isystem`. Clang's include search + # merges all system-tier groups in argument order: `-isystem` + # (System) precedes `-cxx-isystem` (CXXSystem), which precedes + # the `-internal-isystem` cuda_wrappers entry clang's CUDA + # driver adds automatically. That automatic entry therefore + # sorts *after* the C++ stdlib and never intercepts headers + # like bits/shared_ptr_base.h via `#include_next`. Adding the + # same dir as `-isystem` here reorders it ahead of the stdlib; + # clang dedups the now-redundant `-internal-isystem` copy + # (RemoveDuplicates keeps the earlier occurrence), so this is + # safe even when the driver also adds it. Note `-idirafter` + # would not work: it lands in the `After` group, searched last, + # behind the C++ stdlib. + flag_groups = [ + flag_group(flags = ["-isystem", d]) + for d in cuda_wrappers_dirs + ], + ), + ] if cuda_wrappers_dirs else [], + ) + features = [ clang_compile_env_feature, + cuda_wrappers_include_feature, cuda_path_feature, supports_compiler_device_link_feature, supports_wrapper_device_link_feature,