History

rust: rust_is_available: warn for `bindgen` < 0.72.1 && libclang >= 22

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 ]

Miguel Ojeda committed 3 months ago

Commit dc01dfb1 parent fe39a233 files · +48 −1Browse files

Showing the changes to scripts (3 of 3 files). Show all

Unified · Split

3 files
  1. scripts/rust_is_available.sh +14 −0
  2. scripts/rust_is_available_bindgen_libclang_22.h +5 −0
  3. scripts/rust_is_available_test.py +29 −1
scripts/rust_is_available.sh+14−0
@@ -208,6 +208,20 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then · 207 unmodified lines
208208 exit 1
209209 fi
210210
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+
211225 # If the C compiler is Clang, then we can also check whether its version
212226 # matches the `libclang` version used by the Rust bindings generator.
213227 #
scripts/rust_is_available_bindgen_libclang_22.h+5−0
@@ -0,0 +1,5 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+struct S;
3+struct S {
4+ int foo;
5+};
scripts/rust_is_available_test.py+29−1
@@ -54,16 +54,23 @@ else: · 53 unmodified lines
5454 """)
5555
5656 @classmethod
57− def generate_bindgen(cls, version_stdout, libclang_stderr):
57+ def generate_bindgen(cls, version_stdout, libclang_stderr, libclang_22_patched=False):
5858 if libclang_stderr is None:
5959 libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
6060 else:
6161 libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"
6262
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+
6368 return cls.generate_executable(f"""#!/usr/bin/env python3
6469 import sys
6570 if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
6671 {libclang_case}
72+elif "rust_is_available_bindgen_libclang_22.h" in " ".join(sys.argv):
73+ {libclang_22_case}
6774 else:
6875 print({repr(version_stdout)})
6976 """)
@@ -260,6 +267,27 @@ else: · 190 unmodified lines
260267 result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
261268 self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr)
262269
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+
263291 def test_clang_matches_bindgen_libclang_different_bindgen(self):
264292 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")
265293 result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t