rust: allow linking with sanitizer-enabled C libraries

Fixes: #15222
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index 73c3814..16700ad 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -213,6 +213,22 @@
     def get_crt_static(self) -> bool:
         return 'target_feature="crt-static"' in self.get_cfgs()
 
+    def get_nightly(self, target: T.Optional[BuildTarget], env: Environment) -> bool:
+        if not target:
+            return self.allow_nightly
+        key = self.form_compileropt_key('nightly')
+        nightly_opt = env.coredata.get_option_for_target(target, key)
+        if nightly_opt == 'enabled' and not self.is_nightly:
+            raise EnvironmentException(f'Rust compiler {self.name_string()} is not a nightly compiler as required by the "nightly" option.')
+        return nightly_opt != 'disabled' and self.is_nightly
+
+    def sanitizer_link_args(self, target: T.Optional[BuildTarget], env: Environment, value: T.List[str]) -> T.List[str]:
+        # Sanitizers are not supported yet for Rust code.  Nightly supports that
+        # with -Zsanitizer=, but procedural macros cannot use them.  But even if
+        # Rust code cannot be instrumented, we can link in the sanitizer libraries
+        # for the sake of C/C++ code
+        return rustc_link_args(super().sanitizer_link_args(target, env, value))
+
     @functools.lru_cache(maxsize=None)
     def has_verbatim(self) -> bool:
         if version_compare(self.version, '< 1.67.0'):
diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py
index 60069ac..8ab99d9 100644
--- a/unittests/linuxliketests.py
+++ b/unittests/linuxliketests.py
@@ -1968,6 +1968,23 @@
             self.check_has_flag(compdb, sub1src, '-O2')
             self.check_has_flag(compdb, sub2src, '-O2')
 
+    @skip_if_not_language('rust')
+    @skip_if_not_base_option('b_sanitize')
+    def test_rust_sanitizers(self):
+        args = ['-Drust_nightly=disabled', '-Db_lundef=false']
+        testdir = os.path.join(self.rust_test_dir, '28 mixed')
+        tests = ['address']
+
+        env = get_fake_env(testdir, self.builddir, self.prefix)
+        cpp = detect_cpp_compiler(env, MachineChoice.HOST)
+        if cpp.find_library('ubsan', env, []):
+            tests += ['address,undefined']
+
+        for value in tests:
+            self.init(testdir, extra_args=args + ['-Db_sanitize=' + value])
+            self.build()
+            self.wipe()
+
     def test_sanitizers(self):
         testdir = os.path.join(self.unit_test_dir, '128 sanitizers')