From b16e3e778b48ad294ddaa607521f699b39c8b47d Mon Sep 17 00:00:00 2001 From: Sorin Albu-Irimies Date: Sat, 7 Nov 2026 16:14:32 +0100 Subject: [PATCH] fix(spirv-builder): error instead of panic when backend dylib is missing `find_rustc_codegen_spirv` now returns `SpirvBuilderError::RustcCodegenSpirvDylibNotFound` (the enum is `#[non_exhaustive]`, so this is non-breaking). Adds dylib lookup tests. --- crates/spirv-builder/src/lib.rs | 12 +++++---- crates/spirv-builder/src/tests.rs | 41 ++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/crates/spirv-builder/src/lib.rs b/crates/spirv-builder/src/lib.rs index cd19f00862e..3225b4813a6 100644 --- a/crates/spirv-builder/src/lib.rs +++ b/crates/spirv-builder/src/lib.rs @@ -110,6 +110,8 @@ pub enum SpirvBuilderError { "Without feature `rustc_codegen_spirv`, you need to set the path of the dylib with `rustc_codegen_spirv_location`" )] MissingRustcCodegenSpirvDylib, + #[error("could not find `{filename}` in the dynamic library search path")] + RustcCodegenSpirvDylibNotFound { filename: String }, #[error("`rustc_codegen_spirv_location` path '{0}' is not a file")] RustcCodegenSpirvDylibDoesNotExist(PathBuf), #[error("build failed")] @@ -863,11 +865,11 @@ fn find_rustc_codegen_spirv_in_paths(dylib_paths: Vec) -> Option Result { if cfg!(feature = "rustc_codegen_spirv") { - if let Some(path) = find_rustc_codegen_spirv_in_paths(dylib_path()) { - return Ok(path); - } - let filename = rustc_codegen_spirv_dylib_name(); - panic!("Could not find {filename} in library path"); + find_rustc_codegen_spirv_in_paths(dylib_path()).ok_or_else(|| { + SpirvBuilderError::RustcCodegenSpirvDylibNotFound { + filename: rustc_codegen_spirv_dylib_name(), + } + }) } else { Err(SpirvBuilderError::MissingRustcCodegenSpirvDylib) } diff --git a/crates/spirv-builder/src/tests.rs b/crates/spirv-builder/src/tests.rs index 6b37072be07..6c44d063437 100644 --- a/crates/spirv-builder/src/tests.rs +++ b/crates/spirv-builder/src/tests.rs @@ -20,7 +20,9 @@ mod clap { } mod dylib_lookup { - use crate::{find_rustc_codegen_spirv_in_paths, rustc_codegen_spirv_dylib_name}; + use crate::{ + SpirvBuilderError, find_rustc_codegen_spirv_in_paths, rustc_codegen_spirv_dylib_name, + }; use std::fs; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -52,6 +54,43 @@ mod dylib_lookup { } } + #[test] + fn finds_nothing_in_empty_or_missing_dirs() { + let empty = TempDir::new("empty"); + let missing = empty.path().join("does-not-exist"); + + assert_eq!(find_rustc_codegen_spirv_in_paths(vec![]), None); + assert_eq!( + find_rustc_codegen_spirv_in_paths(vec![empty.path().to_path_buf(), missing]), + None + ); + } + + #[test] + fn ignores_unrelated_dylibs() { + let dir = TempDir::new("unrelated"); + let unrelated = dir.path().join(format!( + "{}some_other_backend{}", + std::env::consts::DLL_PREFIX, + std::env::consts::DLL_SUFFIX + )); + fs::File::create(&unrelated).expect("failed to create unrelated dylib file"); + + assert_eq!( + find_rustc_codegen_spirv_in_paths(vec![dir.path().to_path_buf()]), + None + ); + } + + /// A missing backend dylib is reported as an error (it used to `panic!`). + #[test] + fn not_found_error_names_the_dylib() { + let err = SpirvBuilderError::RustcCodegenSpirvDylibNotFound { + filename: rustc_codegen_spirv_dylib_name(), + }; + assert!(err.to_string().contains(&rustc_codegen_spirv_dylib_name())); + } + #[test] fn finds_exact_backend_dylib() { let dir = TempDir::new("exact");