From b6aa425bd7bb4da2a16562068505750d241be6ac Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Thu, 4 Jun 2026 13:30:50 -0400 Subject: [PATCH 1/2] test(bindeps): cover transitive artifact target download Add coverage for a git dependency whose build script has a path artifact build-dependency with an explicit target. This matches the topology from #16881 and records the expected successful build behavior before changing target loading. --- tests/testsuite/artifact_dep.rs | 83 ++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/tests/testsuite/artifact_dep.rs b/tests/testsuite/artifact_dep.rs index db28f921e59..622fca2a692 100644 --- a/tests/testsuite/artifact_dep.rs +++ b/tests/testsuite/artifact_dep.rs @@ -9,7 +9,7 @@ use cargo_test_support::compare::assert_e2e; use cargo_test_support::registry::{Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{ - Project, basic_bin_manifest, basic_manifest, cross_compile, project, publish, registry, + Project, basic_bin_manifest, basic_manifest, cross_compile, git, project, publish, registry, rustc_host, }; @@ -3318,6 +3318,87 @@ Caused by: .run(); } +#[cargo_test] +fn transitive_build_script_artifact_dependency_with_valid_target_does_not_panic() { + if cross_compile_disabled() { + return; + } + let target = cross_compile::alternate(); + let fdb = git::new("fdb", |project| { + project + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "fdb" + version = "0.0.0" + edition = "2015" + build = "build.rs" + + [dependencies] + redux_helper32 = {{ path = "redux_helper32/" }} + + [build-dependencies] + redux_helper32 = {{ path = "redux_helper32/", artifact = "bin", target = "{target}" }} + "#, + ), + ) + .file("src/lib.rs", "") + .file( + "build.rs", + r#"fn main() { + let bin = std::env::var_os("CARGO_BIN_FILE_REDUX_HELPER32").unwrap(); + assert!(std::path::PathBuf::from(bin).exists()); + }"#, + ) + .file( + "redux_helper32/Cargo.toml", + r#" + [package] + name = "redux_helper32" + version = "0.0.0" + edition = "2015" + "#, + ) + .file("redux_helper32/src/lib.rs", "") + .file("redux_helper32/src/main.rs", "fn main() {}") + }); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.0.0" + edition = "2015" + + [dependencies] + fdb = {{ git = '{}' }} + "#, + fdb.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check -Z bindeps") + .masquerade_as_nightly_cargo(&["bindeps"]) + .with_stderr_data(str![[r#" +[UPDATING] git repository `[ROOTURL]/fdb` +[LOCKING] 2 packages to latest compatible versions +[COMPILING] redux_helper32 v0.0.0 ([ROOTURL]/fdb#[..]) +[COMPILING] fdb v0.0.0 ([ROOTURL]/fdb#[..]) +[CHECKING] foo v0.0.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .with_status(0) + .run(); +} + #[cargo_test] fn build_only_specified_artifact_library() { // Create a project with: From b72f42d46095a1927c285e641a76e0336e74321e Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Thu, 4 Jun 2026 13:30:50 -0400 Subject: [PATCH 2/2] fix(bindeps): load targets before downloading artifacts Artifact dependencies can introduce additional compile targets through manifest target fields. Cargo loaded those targets during feature resolution for some paths, but PackageSet::download_accessible could encounter a transitive artifact build-dependency before the target data had been populated. When that happened, dependency platform filtering asked for cfg data for an unknown target and panicked. Load artifact dependency targets during the same traversal that follows them for downloads, so target cfg data is available before filtering recurses into that target. Closes #16881. --- src/cargo/core/package.rs | 52 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index e0f0e5f96cf..917a844f353 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -622,7 +622,7 @@ impl<'gctx> PackageSet<'gctx> { root_ids: &[PackageId], has_dev_units: HasDevUnits, requested_kinds: &[CompileKind], - target_data: &RustcTargetData<'gctx>, + target_data: &mut RustcTargetData<'gctx>, force_all_targets: ForceAllTargets, ) -> CargoResult<()> { fn collect_used_deps( @@ -631,7 +631,7 @@ impl<'gctx> PackageSet<'gctx> { pkg_id: PackageId, has_dev_units: HasDevUnits, requested_kind: CompileKind, - target_data: &RustcTargetData<'_>, + target_data: &mut RustcTargetData<'_>, force_all_targets: ForceAllTargets, ) -> CargoResult<()> { if !used.insert((pkg_id, requested_kind)) { @@ -645,29 +645,45 @@ impl<'gctx> PackageSet<'gctx> { requested_kinds, target_data, force_all_targets, - ); - for (pkg_id, deps) in filtered_deps { + ) + .map(|(dep_pkg_id, deps)| { + let artifact_kinds = deps + .iter() + .filter_map(|dep| { + Some(( + dep.artifact()? + .target()? + .to_resolved_compile_kind(requested_kind), + dep.name_in_toml(), + )) + }) + .collect::>(); + (dep_pkg_id, artifact_kinds) + }) + .collect::>(); + for (dep_pkg_id, deps) in filtered_deps { collect_used_deps( used, resolve, - pkg_id, + dep_pkg_id, has_dev_units, requested_kind, target_data, force_all_targets, )?; - let artifact_kinds = deps.iter().filter_map(|dep| { - Some( - dep.artifact()? - .target()? - .to_resolved_compile_kind(*requested_kinds.iter().next().unwrap()), - ) - }); - for artifact_kind in artifact_kinds { + for (artifact_kind, dep_name) in deps { + let target_name = target_data.short_name(&artifact_kind).to_owned(); + target_data.merge_compile_kind(artifact_kind).with_context(|| { + format!( + "failed to determine target information for target `{target_name}`.\n \ + Artifact dependency `{dep_name}` in package `{pkg_id}` requires \ + building for `{target_name}`" + ) + })?; collect_used_deps( used, resolve, - pkg_id, + dep_pkg_id, has_dev_units, artifact_kind, target_data, @@ -678,6 +694,14 @@ impl<'gctx> PackageSet<'gctx> { Ok(()) } + let default_kinds; + let requested_kinds = if requested_kinds.is_empty() { + default_kinds = [CompileKind::Host]; + &default_kinds + } else { + requested_kinds + }; + // This is sorted by PackageId to get consistent behavior and error // messages for Cargo's testsuite. Perhaps there is a better ordering // that optimizes download time?