From b2e7ae1f65fd5e1579692a9a7a8c95fb95aa1b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Aug 2024 15:08:43 +0000 Subject: [PATCH 01/11] Detect multiple crate versions on method not found When a type comes indirectly from one crate version but the imported trait comes from a separate crate version, the called method won't be found. We now show additional context: ``` error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope --> multiple-dep-versions.rs:8:10 | 8 | Type.foo(); | ^^^ method not found in `Type` | note: you have multiple different versions of crate `dependency` in your dependency graph --> multiple-dep-versions.rs:4:32 | 4 | use dependency::{do_something, Trait}; | ^^^^^ `dependency` imported here doesn't correspond to the right crate version | ::: ~/rust/build/x86_64-unknown-linux-gnu/test/run-make/crate-loading/rmake_out/multiple-dep-versions-1.rs:4:1 | 4 | pub trait Trait { | --------------- this is the trait that was imported | ::: ~/rust/build/x86_64-unknown-linux-gnu/test/run-make/crate-loading/rmake_out/multiple-dep-versions-2.rs:4:1 | 4 | pub trait Trait { | --------------- this is the trait that is needed 5 | fn foo(&self); | --- the method is available for `dep_2_reexport::Type` here ``` --- .../rustc_hir_typeck/src/method/suggest.rs | 69 +++++++++++++++++-- .../crate-loading/multiple-dep-versions-1.rs | 10 ++- .../crate-loading/multiple-dep-versions-2.rs | 10 ++- .../crate-loading/multiple-dep-versions-3.rs | 5 ++ .../crate-loading/multiple-dep-versions.rs | 5 +- tests/run-make/crate-loading/rmake.rs | 14 +++- 6 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 tests/run-make/crate-loading/multiple-dep-versions-3.rs diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 61287d98676b2..d4fcbcad7ae07 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3448,6 +3448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_missing_method: bool, ) { let mut alt_rcvr_sugg = false; + let mut suggest = true; if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { debug!( "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}", @@ -3491,10 +3492,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let did = Some(pick.item.container_id(self.tcx)); let skip = skippable.contains(&did); if pick.autoderefs == 0 && !skip { - err.span_label( - pick.item.ident(self.tcx).span, - format!("the method is available for `{rcvr_ty}` here"), + suggest = self.detect_and_explain_multiple_crate_versions( + err, + &pick.item, + rcvr.hir_id.owner, + *rcvr_ty, ); + if suggest { + err.span_label( + pick.item.ident(self.tcx).span, + format!("the method is available for `{rcvr_ty}` here"), + ); + } } break; } @@ -3675,7 +3684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) { + if suggest && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) { return; } @@ -4040,6 +4049,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn detect_and_explain_multiple_crate_versions( + &self, + err: &mut Diag<'_>, + item: &ty::AssocItem, + owner: hir::OwnerId, + rcvr_ty: Ty<'_>, + ) -> bool { + let pick_name = self.tcx.crate_name(item.def_id.krate); + if let Some(map) = self.tcx.in_scope_traits_map(owner) { + for trait_candidate in map.to_sorted_stable_ord().into_iter().flat_map(|v| v.1.iter()) { + let name = self.tcx.crate_name(trait_candidate.def_id.krate); + if trait_candidate.def_id.krate != item.def_id.krate && name == pick_name { + let msg = format!( + "you have multiple different versions of crate `{name}` in your \ + dependency graph", + ); + let tdid = self.tcx.parent(item.def_id); + if self.tcx.item_name(trait_candidate.def_id) == self.tcx.item_name(tdid) + && let Some(def_id) = trait_candidate.import_ids.get(0) + { + let span = self.tcx.def_span(*def_id); + let mut multi_span: MultiSpan = span.into(); + multi_span.push_span_label( + span, + format!( + "`{name}` imported here doesn't correspond to the right crate \ + version", + ), + ); + multi_span.push_span_label( + self.tcx.def_span(trait_candidate.def_id), + format!("this is the trait that was imported"), + ); + multi_span.push_span_label( + self.tcx.def_span(tdid), + format!("this is the trait that is needed"), + ); + multi_span.push_span_label( + item.ident(self.tcx).span, + format!("the method is available for `{rcvr_ty}` here"), + ); + err.span_note(multi_span, msg); + return false; + } else { + err.note(msg); + } + } + } + } + true + } + /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else` /// FIXME: currently not working for suggesting `map_or_else`, see #102408 pub(crate) fn suggest_else_fn_with_closure( diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs index 2d35163382916..94f30ca326fdb 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs @@ -1,6 +1,10 @@ #![crate_name = "dependency"] #![crate_type = "rlib"] -pub struct Type; -pub trait Trait {} -impl Trait for Type {} +pub struct Type(pub i32); +pub trait Trait { + fn foo(&self); +} +impl Trait for Type { + fn foo(&self) {} +} pub fn do_something(_: X) {} diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs index a5df3dc61eda5..0a4626be5605b 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs @@ -1,6 +1,10 @@ #![crate_name = "dependency"] #![crate_type = "rlib"] -pub struct Type(pub i32); -pub trait Trait {} -impl Trait for Type {} +pub struct Type; +pub trait Trait { + fn foo(&self); +} +impl Trait for Type { + fn foo(&self) {} +} pub fn do_something(_: X) {} diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/multiple-dep-versions-3.rs new file mode 100644 index 0000000000000..07d888e9f1034 --- /dev/null +++ b/tests/run-make/crate-loading/multiple-dep-versions-3.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] +#![crate_type = "rlib"] + +extern crate dependency; +pub use dependency::Type; diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs index 5a6cb03aaa4a7..113a6b76d7d82 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions.rs @@ -1,8 +1,9 @@ extern crate dep_2_reexport; extern crate dependency; -use dep_2_reexport::do_something; -use dependency::Type; +use dep_2_reexport::Type; +use dependency::{do_something, Trait}; fn main() { do_something(Type); + Type.foo(); } diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index d7abd5872c94a..5da706624aef7 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -7,11 +7,15 @@ use run_make_support::{rust_lib_name, rustc}; fn main() { rustc().input("multiple-dep-versions-1.rs").run(); rustc().input("multiple-dep-versions-2.rs").extra_filename("2").metadata("2").run(); + rustc() + .input("multiple-dep-versions-3.rs") + .extern_("dependency", rust_lib_name("dependency2")) + .run(); rustc() .input("multiple-dep-versions.rs") .extern_("dependency", rust_lib_name("dependency")) - .extern_("dep_2_reexport", rust_lib_name("dependency2")) + .extern_("dep_2_reexport", rust_lib_name("foo")) .run_fail() .assert_stderr_contains( "you have multiple different versions of crate `dependency` in your dependency graph", @@ -22,5 +26,11 @@ fn main() { ) .assert_stderr_contains("this type doesn't implement the required trait") .assert_stderr_contains("this type implements the required trait") - .assert_stderr_contains("this is the required trait"); + .assert_stderr_contains("this is the required trait") + .assert_stderr_contains( + "`dependency` imported here doesn't correspond to the right crate version", + ) + .assert_stderr_contains("this is the trait that was imported") + .assert_stderr_contains("this is the trait that is needed") + .assert_stderr_contains("the method is available for `dep_2_reexport::Type` here"); } From 5c427b4600708dce24066ade292f8d8b592b1cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Aug 2024 16:18:06 +0000 Subject: [PATCH 02/11] reword message --- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- .../src/error_reporting/traits/fulfillment_errors.rs | 4 ++-- tests/run-make/crate-loading/rmake.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d4fcbcad7ae07..6afbde867398a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4062,7 +4062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let name = self.tcx.crate_name(trait_candidate.def_id.krate); if trait_candidate.def_id.krate != item.def_id.krate && name == pick_name { let msg = format!( - "you have multiple different versions of crate `{name}` in your \ + "there are multiple different versions of crate `{name}` in the \ dependency graph", ); let tdid = self.tcx.parent(item.def_id); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 95d4509c100a2..5b879cf67ce0d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1697,11 +1697,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.highlighted_span_help( span, vec![ - StringPart::normal("you have ".to_string()), + StringPart::normal("there are ".to_string()), StringPart::highlighted("multiple different versions".to_string()), StringPart::normal(" of crate `".to_string()), StringPart::highlighted(format!("{name}")), - StringPart::normal("` in your dependency graph".to_string()), + StringPart::normal("` the your dependency graph".to_string()), ], ); let candidates = if impl_candidates.is_empty() { diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 5da706624aef7..1b9c13c1f6a10 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -18,7 +18,7 @@ fn main() { .extern_("dep_2_reexport", rust_lib_name("foo")) .run_fail() .assert_stderr_contains( - "you have multiple different versions of crate `dependency` in your dependency graph", + "there are multiple different versions of crate `dependency` in the dependency graph", ) .assert_stderr_contains( "two types coming from two different versions of the same crate are different types \ From eeb72835d291a9e5fc08731ed0e26cc707ced720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Aug 2024 21:09:17 +0000 Subject: [PATCH 03/11] Account for fully-qualified path case of conflicting crate versions When encountering the following, mention the precense of conflicting crates: ``` error[E0599]: no function or associated item named `get_decoded` found for struct `HpkeConfig` in the current scope --> src/main.rs:7:17 | 7 | HpkeConfig::get_decoded(&foo); | ^^^^^^^^^^^ function or associated item not found in `HpkeConfig` | note: if you're trying to build a new `HpkeConfig`, consider using `HpkeConfig::new` which returns `HpkeConfig` --> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/janus_messages-0.3.1/src/lib.rs:908:5 | 908 | / pub fn new( 909 | | id: HpkeConfigId, 910 | | kem_id: HpkeKemId, 911 | | kdf_id: HpkeKdfId, 912 | | aead_id: HpkeAeadId, 913 | | public_key: HpkePublicKey, 914 | | ) -> HpkeConfig { | |___________________^ note: there are multiple different versions of crate `prio` in the dependency graph --> src/main.rs:1:5 | 1 | use prio::codec::Decode; | ^^^^^^^^^^^^^^^^^^^ `prio` imported here doesn't correspond to the right crate version | ::: ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/prio-0.9.1/src/codec.rs:35:1 | 35 | pub trait Decode: Sized { | ----------------------- this is the trait that was imported | ::: ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/prio-0.10.3/src/codec.rs:35:1 | 35 | pub trait Decode: Sized { | ----------------------- this is the trait that is needed ... 43 | fn get_decoded(bytes: &[u8]) -> Result { | -------------------------------------------------------- the method is available for `HpkeConfig` here help: there is an associated function `decode` with a similar name | 7 | HpkeConfig::decode(&foo); | ~~~~~~ ``` --- .../rustc_hir_typeck/src/method/suggest.rs | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6afbde867398a..4ab7e2ee17772 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3494,7 +3494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pick.autoderefs == 0 && !skip { suggest = self.detect_and_explain_multiple_crate_versions( err, - &pick.item, + pick.item.def_id, + pick.item.ident(self.tcx).span, rcvr.hir_id.owner, *rcvr_ty, ); @@ -3684,6 +3685,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + + if let SelfSource::QPath(ty) = source + && !valid_out_of_scope_traits.is_empty() + && let hir::TyKind::Path(path) = ty.kind + && let hir::QPath::Resolved(_, path) = path + && let Some(def_id) = path.res.opt_def_id() + && let Some(assoc) = self + .tcx + .associated_items(valid_out_of_scope_traits[0]) + .filter_by_name_unhygienic(item_name.name) + .next() + { + // See if the `Type::function(val)` where `function` wasn't found corresponds to a + // `Trait` that is imported directly, but `Type` came from a different version of the + // same crate. + let rcvr_ty = self.tcx.type_of(def_id).instantiate_identity(); + suggest = self.detect_and_explain_multiple_crate_versions( + err, + assoc.def_id, + self.tcx.def_span(assoc.def_id), + ty.hir_id.owner, + rcvr_ty, + ); + } if suggest && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) { return; } @@ -4052,21 +4077,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn detect_and_explain_multiple_crate_versions( &self, err: &mut Diag<'_>, - item: &ty::AssocItem, + item_def_id: DefId, + item_span: Span, owner: hir::OwnerId, rcvr_ty: Ty<'_>, ) -> bool { - let pick_name = self.tcx.crate_name(item.def_id.krate); + let pick_name = self.tcx.crate_name(item_def_id.krate); + let trait_did = self.tcx.parent(item_def_id); + let trait_name = self.tcx.item_name(trait_did); if let Some(map) = self.tcx.in_scope_traits_map(owner) { for trait_candidate in map.to_sorted_stable_ord().into_iter().flat_map(|v| v.1.iter()) { - let name = self.tcx.crate_name(trait_candidate.def_id.krate); - if trait_candidate.def_id.krate != item.def_id.krate && name == pick_name { + let crate_name = self.tcx.crate_name(trait_candidate.def_id.krate); + if trait_candidate.def_id.krate != item_def_id.krate && crate_name == pick_name { let msg = format!( - "there are multiple different versions of crate `{name}` in the \ + "there are multiple different versions of crate `{crate_name}` in the \ dependency graph", ); - let tdid = self.tcx.parent(item.def_id); - if self.tcx.item_name(trait_candidate.def_id) == self.tcx.item_name(tdid) + let candidate_name = self.tcx.item_name(trait_candidate.def_id); + if candidate_name == trait_name && let Some(def_id) = trait_candidate.import_ids.get(0) { let span = self.tcx.def_span(*def_id); @@ -4074,8 +4102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { multi_span.push_span_label( span, format!( - "`{name}` imported here doesn't correspond to the right crate \ - version", + "`{crate_name}` imported here doesn't correspond to the right \ + crate version", ), ); multi_span.push_span_label( @@ -4083,11 +4111,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("this is the trait that was imported"), ); multi_span.push_span_label( - self.tcx.def_span(tdid), + self.tcx.def_span(trait_did), format!("this is the trait that is needed"), ); multi_span.push_span_label( - item.ident(self.tcx).span, + item_span, format!("the method is available for `{rcvr_ty}` here"), ); err.span_note(multi_span, msg); From 4e985534e850822c6e1069b6bb2459b31ea5a886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Aug 2024 21:24:49 +0000 Subject: [PATCH 04/11] Ignore auto-deref for multiple crate version note As per the case presented in #128569, we should be showing the extra info even if auto-deref is involved. --- .../rustc_hir_typeck/src/method/suggest.rs | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4ab7e2ee17772..cf9f496ed56ff 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3448,7 +3448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_missing_method: bool, ) { let mut alt_rcvr_sugg = false; - let mut suggest = true; + let mut trait_in_other_version_found = false; if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { debug!( "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}", @@ -3490,21 +3490,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // self types and rely on the suggestion to `use` the trait from // `suggest_valid_traits`. let did = Some(pick.item.container_id(self.tcx)); - let skip = skippable.contains(&did); - if pick.autoderefs == 0 && !skip { - suggest = self.detect_and_explain_multiple_crate_versions( + if skippable.contains(&did) { + continue; + } + trait_in_other_version_found = self + .detect_and_explain_multiple_crate_versions( err, pick.item.def_id, pick.item.ident(self.tcx).span, rcvr.hir_id.owner, *rcvr_ty, ); - if suggest { - err.span_label( - pick.item.ident(self.tcx).span, - format!("the method is available for `{rcvr_ty}` here"), - ); - } + if pick.autoderefs == 0 && !trait_in_other_version_found { + err.span_label( + pick.item.ident(self.tcx).span, + format!("the method is available for `{rcvr_ty}` here"), + ); } break; } @@ -3701,7 +3702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `Trait` that is imported directly, but `Type` came from a different version of the // same crate. let rcvr_ty = self.tcx.type_of(def_id).instantiate_identity(); - suggest = self.detect_and_explain_multiple_crate_versions( + trait_in_other_version_found = self.detect_and_explain_multiple_crate_versions( err, assoc.def_id, self.tcx.def_span(assoc.def_id), @@ -3709,7 +3710,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty, ); } - if suggest && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) { + if !trait_in_other_version_found + && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) + { return; } @@ -4119,14 +4122,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("the method is available for `{rcvr_ty}` here"), ); err.span_note(multi_span, msg); - return false; } else { err.note(msg); } + return true; } } } - true + false } /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else` From 61058937e5a9d58ce1f9c5e0ac6beef22c54cadf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 10 Aug 2024 00:32:10 +0000 Subject: [PATCH 05/11] Rework suggestion method Make checking slightly cheaper (by restricting to the right item only). Add tests. --- .../rustc_hir_typeck/src/method/suggest.rs | 96 +++++++++---------- .../crate-loading/multiple-dep-versions-1.rs | 2 + .../crate-loading/multiple-dep-versions-2.rs | 2 + .../crate-loading/multiple-dep-versions.rs | 1 + tests/run-make/crate-loading/rmake.rs | 84 ++++++++++++++-- 5 files changed, 126 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index cf9f496ed56ff..31366a3076050 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3497,8 +3497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .detect_and_explain_multiple_crate_versions( err, pick.item.def_id, - pick.item.ident(self.tcx).span, - rcvr.hir_id.owner, + rcvr.hir_id, *rcvr_ty, ); if pick.autoderefs == 0 && !trait_in_other_version_found { @@ -3705,8 +3704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_in_other_version_found = self.detect_and_explain_multiple_crate_versions( err, assoc.def_id, - self.tcx.def_span(assoc.def_id), - ty.hir_id.owner, + ty.hir_id, rcvr_ty, ); } @@ -4081,55 +4079,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, item_def_id: DefId, - item_span: Span, - owner: hir::OwnerId, + hir_id: hir::HirId, rcvr_ty: Ty<'_>, ) -> bool { - let pick_name = self.tcx.crate_name(item_def_id.krate); - let trait_did = self.tcx.parent(item_def_id); - let trait_name = self.tcx.item_name(trait_did); - if let Some(map) = self.tcx.in_scope_traits_map(owner) { - for trait_candidate in map.to_sorted_stable_ord().into_iter().flat_map(|v| v.1.iter()) { - let crate_name = self.tcx.crate_name(trait_candidate.def_id.krate); - if trait_candidate.def_id.krate != item_def_id.krate && crate_name == pick_name { - let msg = format!( - "there are multiple different versions of crate `{crate_name}` in the \ - dependency graph", - ); - let candidate_name = self.tcx.item_name(trait_candidate.def_id); - if candidate_name == trait_name - && let Some(def_id) = trait_candidate.import_ids.get(0) - { - let span = self.tcx.def_span(*def_id); - let mut multi_span: MultiSpan = span.into(); - multi_span.push_span_label( - span, - format!( - "`{crate_name}` imported here doesn't correspond to the right \ - crate version", - ), - ); - multi_span.push_span_label( - self.tcx.def_span(trait_candidate.def_id), - format!("this is the trait that was imported"), - ); - multi_span.push_span_label( - self.tcx.def_span(trait_did), - format!("this is the trait that is needed"), - ); - multi_span.push_span_label( - item_span, - format!("the method is available for `{rcvr_ty}` here"), - ); - err.span_note(multi_span, msg); - } else { - err.note(msg); - } - return true; - } + let hir_id = self.tcx.parent_hir_id(hir_id); + let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false }; + if traits.is_empty() { + return false; + } + let trait_def_id = self.tcx.parent(item_def_id); + let krate = self.tcx.crate_name(trait_def_id.krate); + let name = self.tcx.item_name(trait_def_id); + let candidates: Vec<_> = traits + .iter() + .filter(|c| { + c.def_id.krate != trait_def_id.krate + && self.tcx.crate_name(c.def_id.krate) == krate + && self.tcx.item_name(c.def_id) == name + }) + .map(|c| (c.def_id, c.import_ids.get(0).cloned())) + .collect(); + if candidates.is_empty() { + return false; + } + let item_span = self.tcx.def_span(item_def_id); + let msg = format!( + "there are multiple different versions of crate `{krate}` in the dependency graph", + ); + let trait_span = self.tcx.def_span(trait_def_id); + let mut multi_span: MultiSpan = trait_span.into(); + multi_span.push_span_label(trait_span, format!("this is the trait that is needed")); + multi_span + .push_span_label(item_span, format!("the method is available for `{rcvr_ty}` here")); + for (def_id, import_def_id) in candidates { + if let Some(import_def_id) = import_def_id { + multi_span.push_span_label( + self.tcx.def_span(import_def_id), + format!( + "`{name}` imported here doesn't correspond to the right version of crate \ + `{krate}`", + ), + ); } + multi_span.push_span_label( + self.tcx.def_span(def_id), + format!("this is the trait that was imported"), + ); } - false + err.span_note(multi_span, msg); + true } /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else` diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs index 94f30ca326fdb..d81462504dd57 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs @@ -3,8 +3,10 @@ pub struct Type(pub i32); pub trait Trait { fn foo(&self); + fn bar(); } impl Trait for Type { fn foo(&self) {} + fn bar() {} } pub fn do_something(_: X) {} diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs index 0a4626be5605b..0a566fe2c6051 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs @@ -3,8 +3,10 @@ pub struct Type; pub trait Trait { fn foo(&self); + fn bar(); } impl Trait for Type { fn foo(&self) {} + fn bar() {} } pub fn do_something(_: X) {} diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs index 113a6b76d7d82..8ef042bf41842 100644 --- a/tests/run-make/crate-loading/multiple-dep-versions.rs +++ b/tests/run-make/crate-loading/multiple-dep-versions.rs @@ -6,4 +6,5 @@ use dependency::{do_something, Trait}; fn main() { do_something(Type); Type.foo(); + Type::bar(); } diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 1b9c13c1f6a10..65cbc8b0b1b96 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -1,6 +1,7 @@ //@ only-linux //@ ignore-wasm32 //@ ignore-wasm64 +// ignore-tidy-linelength use run_make_support::{rust_lib_name, rustc}; @@ -18,19 +19,82 @@ fn main() { .extern_("dep_2_reexport", rust_lib_name("foo")) .run_fail() .assert_stderr_contains( - "there are multiple different versions of crate `dependency` in the dependency graph", + r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied + --> multiple-dep-versions.rs:7:18 + | +7 | do_something(Type); + | ------------ ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type` + | | + | required by a bound introduced by this call + | +help: there are multiple different versions of crate `dependency` the your dependency graph + --> multiple-dep-versions.rs:1:1 + | +1 | extern crate dep_2_reexport; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a dependency of crate `foo` +2 | extern crate dependency; + | ^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a direct dependency of the current crate"#, ) .assert_stderr_contains( - "two types coming from two different versions of the same crate are different types \ - even if they look the same", + r#" +3 | pub struct Type(pub i32); + | ^^^^^^^^^^^^^^^ this type implements the required trait +4 | pub trait Trait { + | --------------- this is the required trait"#, ) - .assert_stderr_contains("this type doesn't implement the required trait") - .assert_stderr_contains("this type implements the required trait") - .assert_stderr_contains("this is the required trait") .assert_stderr_contains( - "`dependency` imported here doesn't correspond to the right crate version", + r#" +3 | pub struct Type; + | ^^^^^^^^^^^^^^^ this type doesn't implement the required trait"#, ) - .assert_stderr_contains("this is the trait that was imported") - .assert_stderr_contains("this is the trait that is needed") - .assert_stderr_contains("the method is available for `dep_2_reexport::Type` here"); + .assert_stderr_contains( + r#" +error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope + --> multiple-dep-versions.rs:8:10 + | +8 | Type.foo(); + | ^^^ method not found in `Type` + | +note: there are multiple different versions of crate `dependency` in the dependency graph"#, + ) + .assert_stderr_contains( + r#" +4 | pub trait Trait { + | ^^^^^^^^^^^^^^^ this is the trait that is needed +5 | fn foo(&self); + | -------------- the method is available for `dep_2_reexport::Type` here + | + ::: multiple-dep-versions.rs:4:32 + | +4 | use dependency::{do_something, Trait}; + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, + ) + .assert_stderr_contains( + r#" +4 | pub trait Trait { + | --------------- this is the trait that was imported"#, + ) + .assert_stderr_contains( + r#" +error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope + --> multiple-dep-versions.rs:9:11 + | +9 | Type::bar(); + | ^^^ function or associated item not found in `Type` + | +note: there are multiple different versions of crate `dependency` in the dependency graph"#, + ) + .assert_stderr_contains( + r#" +4 | pub trait Trait { + | ^^^^^^^^^^^^^^^ this is the trait that is needed +5 | fn foo(&self); +6 | fn bar(); + | --------- the method is available for `dep_2_reexport::Type` here + | + ::: multiple-dep-versions.rs:4:32 + | +4 | use dependency::{do_something, Trait}; + | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#, + ); } From 110b19b2b6a9896d4d73b8bd8b735fa9c2503d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 12 Aug 2024 19:45:20 +0000 Subject: [PATCH 06/11] Properly differentiate between methods and assoc fns --- compiler/rustc_hir_typeck/src/method/suggest.rs | 3 ++- tests/run-make/crate-loading/rmake.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 31366a3076050..ab13b31439c04 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -4109,8 +4109,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_span = self.tcx.def_span(trait_def_id); let mut multi_span: MultiSpan = trait_span.into(); multi_span.push_span_label(trait_span, format!("this is the trait that is needed")); + let descr = self.tcx.associated_item(item_def_id).descr(); multi_span - .push_span_label(item_span, format!("the method is available for `{rcvr_ty}` here")); + .push_span_label(item_span, format!("the {descr} is available for `{rcvr_ty}` here")); for (def_id, import_def_id) in candidates { if let Some(import_def_id) = import_def_id { multi_span.push_span_label( diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 65cbc8b0b1b96..13585edf6ccbe 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -90,7 +90,7 @@ note: there are multiple different versions of crate `dependency` in the depende | ^^^^^^^^^^^^^^^ this is the trait that is needed 5 | fn foo(&self); 6 | fn bar(); - | --------- the method is available for `dep_2_reexport::Type` here + | --------- the associated function is available for `dep_2_reexport::Type` here | ::: multiple-dep-versions.rs:4:32 | From 35785ef39fa01250f6c4db6bb08e239f55c308ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Thu, 15 Aug 2024 05:13:05 +0000 Subject: [PATCH 07/11] tests: re-enable `dump-ice-to-disk` for Windows This test was previously flakey on `i686-mingw`, but since some modifications I could no longer make it fail on `i686-mingw`. See for multiple try job runs. --- tests/run-make/dump-ice-to-disk/rmake.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs index 48b4071e06541..08767246b90d0 100644 --- a/tests/run-make/dump-ice-to-disk/rmake.rs +++ b/tests/run-make/dump-ice-to-disk/rmake.rs @@ -14,11 +14,14 @@ //! that `RUSTC_ICE_PATH` takes precedence and no ICE dump is emitted under `METRICS_PATH`. //! //! See . - -//@ ignore-windows -// FIXME(#128911): @jieyouxu: This test is sometimes for whatever forsaken reason flakey in -// `i686-mingw`, and I cannot reproduce it locally. The error messages upon assertion failure in -// this test is intentionally extremely verbose to aid debugging that issue. +//! +//! # Test history +//! +//! - The previous rmake.rs iteration of this test was flakey for unknown reason on `i686-mingw` +//! *specifically*, so assertion failures in this test was made extremely verbose to help +//! diagnose why the ICE messages was different *specifically* on `i686-mingw`. +//! - An attempt is made to re-enable this test on `i686-mingw` (by removing `ignore-windows`). If +//! this test is still flakey, please restore the `ignore-windows` directive. use std::cell::OnceCell; use std::path::{Path, PathBuf}; From 29017e45a1c85afe457765a5d4c77e4fcdebb4f6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 16 Aug 2024 12:42:02 -0700 Subject: [PATCH 08/11] mir/pretty: use `Option` instead of `Either` `Either` is wasteful for a one-or-none iterator, especially since `Once` is already an `option::IntoIter` internally. We don't really need any of the iterator mechanisms in this case, just a single conditional insert. --- compiler/rustc_middle/src/mir/pretty.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f2d8781413096..5dd0e69cf1fe6 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1418,21 +1418,19 @@ pub fn write_allocations<'tcx>( alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id()) } - fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator + '_ { + fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option { match val { - ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => { - Either::Left(std::iter::once(ptr.provenance.alloc_id())) - } - ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()), - ConstValue::ZeroSized => Either::Right(std::iter::empty()), + ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()), + ConstValue::Scalar(interpret::Scalar::Int { .. }) => None, + ConstValue::ZeroSized => None, ConstValue::Slice { .. } => { // `u8`/`str` slices, shouldn't contain pointers that we want to print. - Either::Right(std::iter::empty()) + None } ConstValue::Indirect { alloc_id, .. } => { // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR. // Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor. - Either::Left(std::iter::once(alloc_id)) + Some(alloc_id) } } } @@ -1443,7 +1441,9 @@ pub fn write_allocations<'tcx>( match c.const_ { Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { - self.0.extend(alloc_ids_from_const_val(val)); + if let Some(id) = alloc_id_from_const_val(val) { + self.0.insert(id); + } } } } From 9bc7cea412b31be0faf1fc1e65f39b9b952a43e6 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 16 Aug 2024 23:42:10 +0100 Subject: [PATCH 09/11] Fix `is_val_statically_known` for floats --- compiler/rustc_codegen_llvm/src/context.rs | 2 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 22 ++++-- tests/codegen/is_val_statically_known.rs | 81 +++++++++++++++++++- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index dd3f39eceadb6..1fd9f9e811671 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1000,8 +1000,10 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.is.constant.i64", fn(t_i64) -> i1); ifn!("llvm.is.constant.i128", fn(t_i128) -> i1); ifn!("llvm.is.constant.isize", fn(t_isize) -> i1); + ifn!("llvm.is.constant.f16", fn(t_f16) -> i1); ifn!("llvm.is.constant.f32", fn(t_f32) -> i1); ifn!("llvm.is.constant.f64", fn(t_f64) -> i1); + ifn!("llvm.is.constant.f128", fn(t_f128) -> i1); ifn!("llvm.is.constant.ptr", fn(ptr) -> i1); ifn!("llvm.expect.i1", fn(i1, i1) -> i1); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f5558723d11bf..abfe38d4c0cc6 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -192,14 +192,22 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::is_val_statically_known => { let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); - match self.type_kind(intrinsic_type) { - TypeKind::Pointer | TypeKind::Integer | TypeKind::Float | TypeKind::Double => { - self.call_intrinsic( - &format!("llvm.is.constant.{:?}", intrinsic_type), - &[args[0].immediate()], - ) + let kind = self.type_kind(intrinsic_type); + let intrinsic_name = match kind { + TypeKind::Pointer | TypeKind::Integer => { + Some(format!("llvm.is.constant.{intrinsic_type:?}")) } - _ => self.const_bool(false), + // LLVM float types' intrinsic names differ from their type names. + TypeKind::Half => Some(format!("llvm.is.constant.f16")), + TypeKind::Float => Some(format!("llvm.is.constant.f32")), + TypeKind::Double => Some(format!("llvm.is.constant.f64")), + TypeKind::FP128 => Some(format!("llvm.is.constant.f128")), + _ => None, + }; + if let Some(intrinsic_name) = intrinsic_name { + self.call_intrinsic(&intrinsic_name, &[args[0].immediate()]) + } else { + self.const_bool(false) } } sym::unlikely => self diff --git a/tests/codegen/is_val_statically_known.rs b/tests/codegen/is_val_statically_known.rs index 6af4f353a481c..fe432d3bcc4de 100644 --- a/tests/codegen/is_val_statically_known.rs +++ b/tests/codegen/is_val_statically_known.rs @@ -1,6 +1,7 @@ //@ compile-flags: --crate-type=lib -Zmerge-functions=disabled -O #![feature(core_intrinsics)] +#![feature(f16, f128)] use std::intrinsics::is_val_statically_known; @@ -49,7 +50,7 @@ pub fn _bool_false(b: bool) -> i32 { #[inline] pub fn _iref(a: &u8) -> i32 { - if unsafe { is_val_statically_known(a) } { 5 } else { 4 } + if is_val_statically_known(a) { 5 } else { 4 } } // CHECK-LABEL: @_iref_borrow( @@ -68,7 +69,7 @@ pub fn _iref_arg(a: &u8) -> i32 { #[inline] pub fn _slice_ref(a: &[u8]) -> i32 { - if unsafe { is_val_statically_known(a) } { 7 } else { 6 } + if is_val_statically_known(a) { 7 } else { 6 } } // CHECK-LABEL: @_slice_ref_borrow( @@ -84,3 +85,79 @@ pub fn _slice_ref_arg(a: &[u8]) -> i32 { // CHECK: ret i32 6 _slice_ref(a) } + +#[inline] +pub fn _f16(a: f16) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f16_true( +#[no_mangle] +pub fn _f16_true() -> i32 { + // CHECK: ret i32 1 + _f16(1.0) +} + +// CHECK-LABEL: @_f16_false( +#[no_mangle] +pub fn _f16_false(a: f16) -> i32 { + // CHECK: ret i32 0 + _f16(a) +} + +#[inline] +pub fn _f32(a: f32) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f32_true( +#[no_mangle] +pub fn _f32_true() -> i32 { + // CHECK: ret i32 1 + _f32(1.0) +} + +// CHECK-LABEL: @_f32_false( +#[no_mangle] +pub fn _f32_false(a: f32) -> i32 { + // CHECK: ret i32 0 + _f32(a) +} + +#[inline] +pub fn _f64(a: f64) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f64_true( +#[no_mangle] +pub fn _f64_true() -> i32 { + // CHECK: ret i32 1 + _f64(1.0) +} + +// CHECK-LABEL: @_f64_false( +#[no_mangle] +pub fn _f64_false(a: f64) -> i32 { + // CHECK: ret i32 0 + _f64(a) +} + +#[inline] +pub fn _f128(a: f128) -> i32 { + if is_val_statically_known(a) { 1 } else { 0 } +} + +// CHECK-LABEL: @_f128_true( +#[no_mangle] +pub fn _f128_true() -> i32 { + // CHECK: ret i32 1 + _f128(1.0) +} + +// CHECK-LABEL: @_f128_false( +#[no_mangle] +pub fn _f128_false(a: f128) -> i32 { + // CHECK: ret i32 0 + _f128(a) +} From 70320c1936e2cdf0dd4f79c6539b32dd928d4cc2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 11 Aug 2024 14:25:00 -0400 Subject: [PATCH 10/11] Enable more debuginfo tests on Windows --- tests/debuginfo/drop-locations.rs | 1 - tests/debuginfo/embedded-visualizer.rs | 2 +- tests/debuginfo/empty-string.rs | 2 +- tests/debuginfo/issue-12886.rs | 3 +-- tests/debuginfo/macro-stepping.rs | 1 - tests/debuginfo/numeric-types.rs | 2 +- tests/debuginfo/pretty-huge-vec.rs | 2 +- tests/debuginfo/pretty-slices.rs | 2 +- tests/debuginfo/pretty-std-collections.rs | 1 - tests/debuginfo/pretty-uninitialized-vec.rs | 2 +- tests/debuginfo/thread-names.rs | 2 +- 11 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/debuginfo/drop-locations.rs b/tests/debuginfo/drop-locations.rs index 0777313d19804..2db087dda7967 100644 --- a/tests/debuginfo/drop-locations.rs +++ b/tests/debuginfo/drop-locations.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-android //@ min-lldb-version: 310 //@ ignore-test: #128971 diff --git a/tests/debuginfo/embedded-visualizer.rs b/tests/debuginfo/embedded-visualizer.rs index 69afd273f7735..959dbba7fd73c 100644 --- a/tests/debuginfo/embedded-visualizer.rs +++ b/tests/debuginfo/embedded-visualizer.rs @@ -1,7 +1,7 @@ //@ compile-flags:-g //@ min-gdb-version: 8.1 //@ ignore-lldb -//@ ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows +//@ ignore-windows-gnu: #128981 // === CDB TESTS ================================================================================== diff --git a/tests/debuginfo/empty-string.rs b/tests/debuginfo/empty-string.rs index 35b68ed91c0fc..eac3448bfd510 100644 --- a/tests/debuginfo/empty-string.rs +++ b/tests/debuginfo/empty-string.rs @@ -1,4 +1,4 @@ -//@ ignore-windows failing on win32 bot +//@ ignore-windows-gnu: #128981 //@ ignore-android: FIXME(#10381) //@ compile-flags:-g //@ min-gdb-version: 8.1 diff --git a/tests/debuginfo/issue-12886.rs b/tests/debuginfo/issue-12886.rs index c6cf0dd4e05e3..48250e885374d 100644 --- a/tests/debuginfo/issue-12886.rs +++ b/tests/debuginfo/issue-12886.rs @@ -1,4 +1,3 @@ -//@ ignore-windows failing on 64-bit bots FIXME #17638 //@ ignore-lldb //@ ignore-aarch64 @@ -6,7 +5,7 @@ // gdb-command:run // gdb-command:next -// gdb-check:[...]24[...]let s = Some(5).unwrap(); // #break +// gdb-check:[...]23[...]let s = Some(5).unwrap(); // #break // gdb-command:continue #![feature(omit_gdb_pretty_printer_section)] diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 3edac3c7832f9..35bb6de4fef38 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-android //@ ignore-aarch64 //@ min-lldb-version: 1800 diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index 98bc31e88557a..6f45b69e5e34c 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -1,7 +1,7 @@ //@ compile-flags:-g //@ min-gdb-version: 8.1 -//@ ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows +//@ ignore-windows-gnu: #128981 // Tests the visualizations for `NonZero`, `Wrapping` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. diff --git a/tests/debuginfo/pretty-huge-vec.rs b/tests/debuginfo/pretty-huge-vec.rs index dcf3521175d4c..b88e5db1acb8c 100644 --- a/tests/debuginfo/pretty-huge-vec.rs +++ b/tests/debuginfo/pretty-huge-vec.rs @@ -1,4 +1,4 @@ -//@ ignore-windows failing on win32 bot +//@ ignore-windows-gnu: #128981 //@ ignore-android: FIXME(#10381) //@ compile-flags:-g //@ min-gdb-version: 8.1 diff --git a/tests/debuginfo/pretty-slices.rs b/tests/debuginfo/pretty-slices.rs index 9defa344be03e..44335f5c83b3f 100644 --- a/tests/debuginfo/pretty-slices.rs +++ b/tests/debuginfo/pretty-slices.rs @@ -1,5 +1,5 @@ //@ ignore-android: FIXME(#10381) -//@ ignore-windows +//@ ignore-windows-gnu: #128981 //@ compile-flags:-g // gdb-command: run diff --git a/tests/debuginfo/pretty-std-collections.rs b/tests/debuginfo/pretty-std-collections.rs index 3d5a30d19a9ce..3ec00886e2f40 100644 --- a/tests/debuginfo/pretty-std-collections.rs +++ b/tests/debuginfo/pretty-std-collections.rs @@ -1,4 +1,3 @@ -//@ ignore-windows failing on win32 bot //@ ignore-android: FIXME(#10381) //@ ignore-windows-gnu: #128981 //@ compile-flags:-g diff --git a/tests/debuginfo/pretty-uninitialized-vec.rs b/tests/debuginfo/pretty-uninitialized-vec.rs index 5206ff23fd5ba..ddb751161d8ce 100644 --- a/tests/debuginfo/pretty-uninitialized-vec.rs +++ b/tests/debuginfo/pretty-uninitialized-vec.rs @@ -1,4 +1,4 @@ -//@ ignore-windows failing on win32 bot +//@ ignore-windows-gnu: #128981 //@ ignore-android: FIXME(#10381) //@ compile-flags:-g //@ min-gdb-version: 8.1 diff --git a/tests/debuginfo/thread-names.rs b/tests/debuginfo/thread-names.rs index 6b3b0c7f4b231..265b9271cf306 100644 --- a/tests/debuginfo/thread-names.rs +++ b/tests/debuginfo/thread-names.rs @@ -4,7 +4,7 @@ //@[macos] only-macos //@[win] only-windows //@ ignore-sgx -//@ ignore-windows-gnu +//@ ignore-windows-gnu: gdb on windows-gnu does not print thread names // === GDB TESTS ================================================================================== // From 3116db669c4e80ffdae5a34a8dd9bcfba4b1a9be Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 17 Aug 2024 17:56:00 +1000 Subject: [PATCH 11/11] Port `run-make/libtest-json/validate_json.py` to Rust This is a trivial Python script that simply tries to parse each line of stdin (i.e. the test process output) as JSON, to verify that the overall output is JSON Lines. We can perform the same check directly in `rmake.rs` using `serde_json`. --- tests/run-make/libtest-json/rmake.rs | 15 +++++++++++++-- tests/run-make/libtest-json/validate_json.py | 8 -------- 2 files changed, 13 insertions(+), 10 deletions(-) delete mode 100755 tests/run-make/libtest-json/validate_json.py diff --git a/tests/run-make/libtest-json/rmake.rs b/tests/run-make/libtest-json/rmake.rs index acbd88dc46cb9..c31f4a79b641f 100644 --- a/tests/run-make/libtest-json/rmake.rs +++ b/tests/run-make/libtest-json/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile //@ needs-unwind (test file contains #[should_panic] test) -use run_make_support::{cmd, diff, python_command, rustc}; +use run_make_support::{cmd, diff, rustc, serde_json}; fn main() { rustc().arg("--test").input("f.rs").run(); @@ -21,7 +21,18 @@ fn run_tests(extra_args: &[&str], expected_file: &str) { .run_fail(); let test_stdout = &cmd_out.stdout_utf8(); - python_command().arg("validate_json.py").stdin(test_stdout).run(); + // Verify that the test process output is JSON Lines, i.e. each line is valid JSON. + for (line, n) in test_stdout.lines().zip(1..) { + if let Err(e) = serde_json::from_str::(line) { + panic!( + "could not parse JSON on line {n}: {e}\n\ + \n\ + === STDOUT ===\n\ + {test_stdout}\ + ==============" + ); + } + } diff() .expected_file(expected_file) diff --git a/tests/run-make/libtest-json/validate_json.py b/tests/run-make/libtest-json/validate_json.py deleted file mode 100755 index 657f732f2bffd..0000000000000 --- a/tests/run-make/libtest-json/validate_json.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -import sys -import json - -# Try to decode line in order to ensure it is a valid JSON document -for line in sys.stdin: - json.loads(line)