Starting with LLVM 22, `clang_getTypeDeclaration()` may return a forward declaration instead of the type definition. This made `bindgen` generate opaque types [1][2], which in turn made us fail with e.g. error[E0609]: no field `__bindgen_anon_1` on type `bindings::kernel_param` --> rust/kernel/module_param.rs:78:46 | 78 | let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) }; | ^^^^^^^^^^^^^^^^ unknown field | = note: available field is: `_address` This was fixed in `bindgen` 0.72.1 [3]. In order to clarify what is going on and avoid confusion [4][5], add a warning to `rust_is_available.sh` about it when the versions match, similar to past warnings like the one removed in: commit ae64324ad5c1 ("rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1") In addition, even if the versions match, check if the issue appears to not reproduce with the given binaries, to avoid a warning in such a case. Finally, include tests. [ Nathan, in parallel, updated the instructions of the LLVM+Rust kernel.org toolchains [6] so that `--version` is not passed to `cargo` for `bindgen`, and thus the latest `bindgen` is installed by default, which should help to avoid some of these situations. Thanks! - Miguel ]
Showing the changes to scripts (3 of 3 files). Show all
Unified · Split
| @@ -208,6 +208,20 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then · 207 unmodified lines | |||
| 208 | exit 1 | 208 | exit 1 |
| 209 | fi | 209 | fi |
| 210 | 210 | ||
| 211 | if [ "$bindgen_libclang_cversion" -ge 2200000 ] && | ||
| 212 | [ "$rust_bindings_generator_cversion" -lt 7201 ]; then | ||
| 213 | # Distributions may have patched the issue. | ||
| 214 | if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_22.h | grep -q 'pub foo'; then | ||
| 215 | echo >&2 "***" | ||
| 216 | echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.72.1 together with libclang >= 22" | ||
| 217 | echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/3278)." | ||
| 218 | echo >&2 "*** Your bindgen version: $rust_bindings_generator_version" | ||
| 219 | echo >&2 "*** Your libclang version: $bindgen_libclang_version" | ||
| 220 | echo >&2 "***" | ||
| 221 | warning=1 | ||
| 222 | fi | ||
| 223 | fi | ||
| 224 | |||
| 211 | # If the C compiler is Clang, then we can also check whether its version | 225 | # If the C compiler is Clang, then we can also check whether its version |
| 212 | # matches the `libclang` version used by the Rust bindings generator. | 226 | # matches the `libclang` version used by the Rust bindings generator. |
| 213 | # | 227 | # |
| @@ -0,0 +1,5 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | struct S; | ||
| 3 | struct S { | ||
| 4 | int foo; | ||
| 5 | }; | ||
| @@ -54,16 +54,23 @@ else: · 53 unmodified lines | |||
| 54 | """) | 54 | """) |
| 55 | 55 | ||
| 56 | @classmethod | 56 | @classmethod |
| 57 | def generate_bindgen(cls, version_stdout, libclang_stderr): | 57 | def generate_bindgen(cls, version_stdout, libclang_stderr, libclang_22_patched=False): |
| 58 | if libclang_stderr is None: | 58 | if libclang_stderr is None: |
| 59 | libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" | 59 | libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" |
| 60 | else: | 60 | else: |
| 61 | libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" | 61 | libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)" |
| 62 | 62 | ||
| 63 | if libclang_22_patched: | ||
| 64 | libclang_22_case = "print('pub foo: ::std::os::raw::c_int,')" | ||
| 65 | else: | ||
| 66 | libclang_22_case = "pass" | ||
| 67 | |||
| 63 | return cls.generate_executable(f"""#!/usr/bin/env python3 | 68 | return cls.generate_executable(f"""#!/usr/bin/env python3 |
| 64 | import sys | 69 | import sys |
| 65 | if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): | 70 | if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): |
| 66 | {libclang_case} | 71 | {libclang_case} |
| 72 | elif "rust_is_available_bindgen_libclang_22.h" in " ".join(sys.argv): | ||
| 73 | {libclang_22_case} | ||
| 67 | else: | 74 | else: |
| 68 | print({repr(version_stdout)}) | 75 | print({repr(version_stdout)}) |
| 69 | """) | 76 | """) |
| @@ -260,6 +267,27 @@ else: · 190 unmodified lines | |||
| 260 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) | 267 | result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) |
| 261 | self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) | 268 | self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) |
| 262 | 269 | ||
| 270 | def test_bindgen_bad_libclang_22(self): | ||
| 271 | for (bindgen_version, libclang_version, expected_not_patched) in ( | ||
| 272 | ("0.71.1", "21.1.0", self.Expected.SUCCESS), | ||
| 273 | ("0.71.1", "22.0.0", self.Expected.SUCCESS_WITH_WARNINGS), | ||
| 274 | ("0.71.1", "22.1.0", self.Expected.SUCCESS_WITH_WARNINGS), | ||
| 275 | |||
| 276 | ("0.72.0", "22.0.0", self.Expected.SUCCESS_WITH_WARNINGS), | ||
| 277 | |||
| 278 | ("0.72.1", "22.0.0", self.Expected.SUCCESS), | ||
| 279 | ): | ||
| 280 | with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version): | ||
| 281 | cc = self.generate_clang(f"clang version {libclang_version}") | ||
| 282 | libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false" | ||
| 283 | bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr) | ||
| 284 | result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc }) | ||
| 285 | if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS: | ||
| 286 | self.assertIn(f"Rust bindings generator '{bindgen}' < 0.72.1 together with libclang >= 22", result.stderr) | ||
| 287 | |||
| 288 | bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_22_patched=True) | ||
| 289 | result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc }) | ||
| 290 | |||
| 263 | def test_clang_matches_bindgen_libclang_different_bindgen(self): | 291 | def test_clang_matches_bindgen_libclang_different_bindgen(self): |
| 264 | bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false") | 292 | bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false") |
| 265 | result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) | 293 | result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) |