diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d82d4cc39fb..4fe14c7af2f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -318,7 +318,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // This is still required for many(half of the tests in ui/type-alias-impl-trait) // tests to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); if errors.is_empty() { definition_ty diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8778a19eeda..7a3db191f0c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -209,7 +209,7 @@ pub(crate) fn type_check<'mir, 'tcx>( ); translate_outlives_facts(&mut checker); - let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let opaque_type_values = infcx.take_opaque_types(); let opaque_type_values = opaque_type_values .into_iter() diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index be786569cde..f5f3d5de6b5 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -58,6 +58,6 @@ pub fn is_subtype<'tcx>( // even if they're constrained in our current function. // // It seems very unlikely that this hides any bugs. - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); errors.is_empty() } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ef563360c4c..43795cfba3f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -475,7 +475,7 @@ fn check_opaque_meets_bounds<'tcx>( } } // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); } fn is_enum_of_nonnullable_ptr<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index b260b929beb..7af89934d14 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -424,7 +424,7 @@ fn compare_asyncness<'tcx>( ty::Alias(ty::Opaque, ..) => { // allow both `async fn foo()` and `fn foo() -> impl Future` } - ty::Error(rustc_errors::ErrorGuaranteed { .. }) => { + ty::Error(_) => { // We don't know if it's ok, but at least it's already an error. } _ => { @@ -1972,22 +1972,6 @@ pub(super) fn check_type_bounds<'tcx>( &outlives_environment, )?; - let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - for (key, value) in constraints { - infcx - .err_ctxt() - .report_mismatched_types( - &ObligationCause::misc( - value.hidden_type.span, - tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()), - ), - tcx.mk_opaque(key.def_id.to_def_id(), key.substs), - value.hidden_type.ty, - TypeError::Mismatch, - ) - .emit(); - } - Ok(()) } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index bb956ddc780..8c24b600644 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -534,8 +534,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_opaque_types(&mut self) { - let opaque_types = - self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let opaque_types = self.fcx.infcx.take_opaque_types(); for (opaque_type_key, decl) in opaque_types { let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 108011013f5..3d49182f0b8 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -156,10 +156,7 @@ impl<'tcx> InferCtxt<'tcx> { /// As the new solver does canonicalization slightly differently, this is also used there /// for now. This should hopefully change fairly soon. pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { - self.inner - .borrow_mut() - .opaque_type_storage - .take_opaque_types() + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 31b546581e4..6bef3f000a5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1338,6 +1338,12 @@ impl<'tcx> InferCtxt<'tcx> { var_infos } + #[instrument(level = "debug", skip(self), ret)] + pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { + debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error); + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index c146902d594..ae4b85c8799 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } - #[instrument(level = "debug", ret)] - pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { - std::mem::take(&mut self.opaque_types) - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 37771693417..7d62d67d64f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -161,6 +161,7 @@ impl<'a> Resolver<'a> { found_use, DiagnosticMode::Normal, path, + "", ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { @@ -690,6 +691,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Pattern, vec![], + "", ); } err @@ -1344,6 +1346,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Normal, vec![], + "", ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -2309,7 +2312,7 @@ enum FoundUse { } /// Whether a binding is part of a pattern or a use statement. Used for diagnostics. -enum DiagnosticMode { +pub(crate) enum DiagnosticMode { Normal, /// The binding is part of a pattern Pattern, @@ -2324,6 +2327,8 @@ pub(crate) fn import_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], + mode: DiagnosticMode, + append: &str, ) { show_candidates( session, @@ -2333,8 +2338,9 @@ pub(crate) fn import_candidates( candidates, Instead::Yes, FoundUse::Yes, - DiagnosticMode::Import, + mode, vec![], + append, ); } @@ -2352,6 +2358,7 @@ fn show_candidates( found_use: FoundUse, mode: DiagnosticMode, path: Vec, + append: &str, ) { if candidates.is_empty() { return; @@ -2416,7 +2423,7 @@ fn show_candidates( // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); + candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0); } err.span_suggestions( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4d896b05526..00f65ac37b6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,6 @@ //! A bunch of methods and structures more or less related to resolving imports. -use crate::diagnostics::{import_candidates, Suggestion}; +use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion}; use crate::Determinacy::{self, *}; use crate::Namespace::*; use crate::{module_to_string, names_to_string, ImportSuggestion}; @@ -402,7 +402,7 @@ struct UnresolvedImportError { label: Option, note: Option, suggestion: Option, - candidate: Option>, + candidates: Option>, } pub struct ImportResolver<'a, 'b> { @@ -475,12 +475,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { errors = vec![]; } if seen_spans.insert(err.span) { - let path = import_path_to_string( - &import.module_path.iter().map(|seg| seg.ident).collect::>(), - &import.kind, - err.span, - ); - errors.push((path, err)); + errors.push((import, err)); prev_root_id = import.root_id; } } else if is_indeterminate { @@ -494,10 +489,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: None, note: None, suggestion: None, - candidate: None, + candidates: None, }; + // FIXME: there should be a better way of doing this than + // formatting this as a string then checking for `::` if path.contains("::") { - errors.push((path, err)) + errors.push((import, err)) } } } @@ -507,7 +504,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) { + fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; } @@ -516,7 +513,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> { const MAX_LABEL_COUNT: usize = 10; let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect()); - let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::>(); + let paths = errors + .iter() + .map(|(import, err)| { + let path = import_path_to_string( + &import.module_path.iter().map(|seg| seg.ident).collect::>(), + &import.kind, + err.span, + ); + format!("`{path}`") + }) + .collect::>(); let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),); let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg); @@ -525,7 +532,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.note(note); } - for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { + for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) { if let Some(label) = err.label { diag.span_label(err.span, label); } @@ -538,14 +545,36 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.multipart_suggestion(&msg, suggestions, applicability); } - if let Some(candidate) = &err.candidate { - import_candidates( - self.r.session, - &self.r.untracked.source_span, - &mut diag, - Some(err.span), - &candidate, - ) + if let Some(candidates) = &err.candidates { + match &import.kind { + ImportKind::Single { nested: false, source, target, .. } => import_candidates( + self.r.session, + &self.r.untracked.source_span, + &mut diag, + Some(err.span), + &candidates, + DiagnosticMode::Import, + (source != target) + .then(|| format!(" as {target}")) + .as_deref() + .unwrap_or(""), + ), + ImportKind::Single { nested: true, source, target, .. } => { + import_candidates( + self.r.session, + &self.r.untracked.source_span, + &mut diag, + None, + &candidates, + DiagnosticMode::Normal, + (source != target) + .then(|| format!(" as {target}")) + .as_deref() + .unwrap_or(""), + ); + } + _ => {} + } } } @@ -707,14 +736,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { String::from("a similar path exists"), Applicability::MaybeIncorrect, )), - candidate: None, + candidates: None, }, None => UnresolvedImportError { span, label: Some(label), note: None, suggestion, - candidate: None, + candidates: None, }, }; return Some(err); @@ -761,7 +790,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { )), note: None, suggestion: None, - candidate: None, + candidates: None, }); } } @@ -873,7 +902,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); let names = resolutions .filter_map(|(BindingKey { ident: i, .. }, resolution)| { - if *i == ident { + if i.name == ident.name { return None; } // Never suggest the same name match *resolution.borrow() { @@ -943,7 +972,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(label), note, suggestion, - candidate: if !parent_suggestion.is_empty() { + candidates: if !parent_suggestion.is_empty() { Some(parent_suggestion) } else { None diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs new file mode 100644 index 00000000000..ddecbb1a8c4 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs @@ -0,0 +1 @@ +pub use crate::spec::aarch64_unknown_fuchsia::target; diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index baf36587147..2b00cda44b5 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions { allow_asm: true, endian, linker_flavor: LinkerFlavor::Bpf, - atomic_cas: false, + atomic_cas: true, dynamic_linking: true, no_builtins: true, panic_strategy: PanicStrategy::Abort, @@ -19,6 +19,10 @@ pub fn opts(endian: Endian) -> TargetOptions { obj_is_bitcode: true, requires_lto: false, singlethread: true, + // When targeting the `v3` cpu in llvm, 32-bit atomics are also supported. + // But making this value change based on the target cpu can be mostly confusing + // and would require a bit of a refactor. + min_atomic_width: Some(64), max_atomic_width: Some(64), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0fafa52a45b..1e80b8b759d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -981,7 +981,7 @@ impl fmt::Display for StackProtector { } macro_rules! supported_targets { - ( $(($triple:literal, $module:ident ),)+ ) => { + ( $(($triple:literal, $module:ident),)+ ) => { $(mod $module;)+ /// List of supported targets @@ -1109,7 +1109,11 @@ supported_targets! { ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), + // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia + ("aarch64-fuchsia", aarch64_fuchsia), ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), + // FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia + ("x86_64-fuchsia", x86_64_fuchsia), ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs new file mode 100644 index 00000000000..96fed097566 --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -0,0 +1 @@ +pub use crate::spec::x86_64_unknown_fuchsia::target; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2bab380dba0..37b40a2f75a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -450,9 +450,6 @@ pub fn impossible_predicates<'tcx>( } let errors = ocx.select_all_or_error(); - // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - let result = !errors.is_empty(); debug!("impossible_predicates = {:?}", result); result diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index f8f74b732ef..f127ef8343f 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -82,7 +82,7 @@ pub fn codegen_select_candidate<'tcx>( // Opaque types may have gotten their hidden types constrained, but we can ignore them safely // as they will get constrained elsewhere, too. // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); Ok(&*tcx.arena.alloc(impl_source)) } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index fc4d4bff24f..99aaf798e41 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1514,6 +1514,18 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// + /// Flattening works on any `IntoIterator` type, including `Option` and `Result`: + /// + /// ``` + /// let options = vec![Some(123), Some(321), None, Some(231)]; + /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); + /// assert_eq!(flattened_options, vec![123, 321, 231]); + /// + /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; + /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); + /// assert_eq!(flattened_results, vec![123, 321, 231]); + /// ``` + /// /// Flattening only removes one level of nesting at a time: /// /// ``` diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b203ecd3844..2771bd2264c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -99,13 +99,20 @@ impl Step for Std { cargo_subcommand(builder.kind), ); std_cargo(builder, target, compiler.stage, &mut cargo); - cargo.args(args(builder)); builder.info(&format!( "Checking stage{} library artifacts ({} -> {})", builder.top_stage, &compiler.host, target )); - run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false); + run_cargo( + builder, + cargo, + args(builder), + &libstd_stamp(builder, compiler, target), + vec![], + true, + false, + ); // We skip populating the sysroot in non-zero stage because that'll lead // to rlib/rmeta conflicts if std gets built during this session. @@ -149,7 +156,6 @@ impl Step for Std { for krate in builder.in_tree_crates("test", Some(target)) { cargo.arg("-p").arg(krate.name); } - cargo.args(args(builder)); builder.info(&format!( "Checking stage{} library test/bench/example targets ({} -> {})", @@ -158,6 +164,7 @@ impl Step for Std { run_cargo( builder, cargo, + args(builder), &libstd_test_stamp(builder, compiler, target), vec![], true, @@ -226,13 +233,20 @@ impl Step for Rustc { for krate in builder.in_tree_crates("rustc-main", Some(target)) { cargo.arg("-p").arg(krate.name); } - cargo.args(args(builder)); builder.info(&format!( "Checking stage{} compiler artifacts ({} -> {})", builder.top_stage, &compiler.host, target )); - run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false); + run_cargo( + builder, + cargo, + args(builder), + &librustc_stamp(builder, compiler, target), + vec![], + true, + false, + ); let libdir = builder.sysroot_libdir(compiler, target); let hostdir = builder.sysroot_libdir(compiler, compiler.host); @@ -279,7 +293,6 @@ impl Step for CodegenBackend { .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); rustc_cargo_env(builder, &mut cargo, target); - cargo.args(args(builder)); builder.info(&format!( "Checking stage{} {} artifacts ({} -> {})", @@ -289,6 +302,7 @@ impl Step for CodegenBackend { run_cargo( builder, cargo, + args(builder), &codegen_backend_stamp(builder, compiler, target, backend), vec![], true, @@ -345,13 +359,19 @@ impl Step for RustAnalyzer { cargo.arg("--benches"); } - cargo.args(args(builder)); - builder.info(&format!( "Checking stage{} {} artifacts ({} -> {})", compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple )); - run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false); + run_cargo( + builder, + cargo, + args(builder), + &stamp(builder, compiler, target), + vec![], + true, + false, + ); /// Cargo's output path in a given stage, compiled by a particular /// compiler for the specified target. @@ -405,8 +425,6 @@ macro_rules! tool_check_step { cargo.arg("--all-targets"); } - cargo.args(args(builder)); - // Enable internal lints for clippy and rustdoc // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 @@ -422,6 +440,7 @@ macro_rules! tool_check_step { run_cargo( builder, cargo, + args(builder), &stamp(builder, compiler, target), vec![], true, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 147ded3a9ee..6b211d3ec6e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -144,6 +144,7 @@ impl Step for Std { run_cargo( builder, cargo, + vec![], &libstd_stamp(builder, compiler, target), target_deps, false, @@ -738,6 +739,7 @@ impl Step for Rustc { run_cargo( builder, cargo, + vec![], &librustc_stamp(builder, compiler, target), vec![], false, @@ -998,7 +1000,7 @@ impl Step for CodegenBackend { "Building stage{} codegen backend {} ({} -> {})", compiler.stage, backend, &compiler.host, target )); - let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false); + let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false); if builder.config.dry_run() { return; } @@ -1422,6 +1424,7 @@ pub fn add_to_sysroot( pub fn run_cargo( builder: &Builder<'_>, cargo: Cargo, + tail_args: Vec, stamp: &Path, additional_target_deps: Vec<(PathBuf, DependencyType)>, is_check: bool, @@ -1448,7 +1451,7 @@ pub fn run_cargo( // files we need to probe for later. let mut deps = Vec::new(); let mut toplevel = Vec::new(); - let ok = stream_cargo(builder, cargo, &mut |msg| { + let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { let (filenames, crate_types) = match msg { CargoMessage::CompilerArtifact { filenames, @@ -1585,6 +1588,7 @@ pub fn run_cargo( pub fn stream_cargo( builder: &Builder<'_>, cargo: Cargo, + tail_args: Vec, cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { let mut cargo = Command::from(cargo); @@ -1604,6 +1608,10 @@ pub fn stream_cargo( } cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); + for arg in tail_args { + cargo.arg(arg); + } + builder.verbose(&format!("running: {:?}", cargo)); let mut child = match cargo.spawn() { Ok(child) => child, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 63026bd44d4..24b033cc0dc 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -72,7 +72,7 @@ impl Step for ToolBuild { builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); - let is_expected = compile::stream_cargo(builder, cargo, &mut |msg| { + let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| { // Only care about big things like the RLS/Cargo for now match tool { "rls" | "cargo" | "clippy-driver" | "miri" | "rustfmt" => {} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7ff26e420f1..16057048259 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -124,6 +124,7 @@ target | std | notes -------|:---:|------- `aarch64-apple-ios` | ✓ | ARM64 iOS [`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64 +`aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia` `aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat @@ -177,6 +178,7 @@ target | std | notes `wasm32-wasi` | ✓ | WebAssembly with WASI `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX +`x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` `x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 77401e8b76e..8ec4631f7d0 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -253,6 +253,7 @@ h1 a, a { color: var(--link-color); + text-decoration: none; } ol, ul { @@ -662,10 +663,6 @@ nav.sub { margin: 0 0 15px 0; } -a { - text-decoration: none; -} - .small-section-header { /* fields use tags, but should get their own lines */ display: block; diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index e89c19b5881..f1f4caee361 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -2,10 +2,7 @@ error[E0432]: unresolved import `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:20:9 | LL | use my_core; - | ^^^^^^^ - | | - | no `my_core` in the root - | help: a similar name exists in the module: `my_core` + | ^^^^^^^ no `my_core` in the root error[E0432]: unresolved import `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:7:13 diff --git a/src/test/ui/imports/bad-import-in-nested.rs b/src/test/ui/imports/bad-import-in-nested.rs new file mode 100644 index 00000000000..2e95480ad41 --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.rs @@ -0,0 +1,27 @@ +// edition: 2021 + +#![allow(unused)] + +mod A { + pub(crate) type AA = (); + pub(crate) type BB = (); + + mod A2 { + use super::{super::C::D::AA, AA as _}; + //~^ ERROR unresolved import + } +} + +mod C { + pub mod D {} +} + +mod B { + use crate::C::{self, AA}; + //~^ ERROR unresolved import + + use crate::{A, C::BB}; + //~^ ERROR unresolved import +} + +fn main() {} diff --git a/src/test/ui/imports/bad-import-in-nested.stderr b/src/test/ui/imports/bad-import-in-nested.stderr new file mode 100644 index 00000000000..855b1e637e9 --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.stderr @@ -0,0 +1,30 @@ +error[E0432]: unresolved import `super::super::C::D::AA` + --> $DIR/bad-import-in-nested.rs:10:21 + | +LL | use super::{super::C::D::AA, AA as _}; + | ^^^^^^^^^^^^^^^ no `AA` in `C::D` + | + = note: consider importing this type alias instead: + crate::A::AA + +error[E0432]: unresolved import `crate::C::AA` + --> $DIR/bad-import-in-nested.rs:20:26 + | +LL | use crate::C::{self, AA}; + | ^^ no `AA` in `C` + | + = note: consider importing this type alias instead: + crate::A::AA + +error[E0432]: unresolved import `crate::C::BB` + --> $DIR/bad-import-in-nested.rs:23:20 + | +LL | use crate::{A, C::BB}; + | ^^^^^ no `BB` in `C` + | + = note: consider importing this type alias instead: + crate::A::BB + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/imports/bad-import-with-rename.rs b/src/test/ui/imports/bad-import-with-rename.rs new file mode 100644 index 00000000000..ffe56916f92 --- /dev/null +++ b/src/test/ui/imports/bad-import-with-rename.rs @@ -0,0 +1,16 @@ +mod A { + pub type B = (); + pub type B2 = (); +} + +mod C { + use crate::D::B as _; + //~^ ERROR unresolved import `crate::D::B` + + use crate::D::B2; + //~^ ERROR unresolved import `crate::D::B2` +} + +mod D {} + +fn main() {} diff --git a/src/test/ui/imports/bad-import-with-rename.stderr b/src/test/ui/imports/bad-import-with-rename.stderr new file mode 100644 index 00000000000..cace2a7a51c --- /dev/null +++ b/src/test/ui/imports/bad-import-with-rename.stderr @@ -0,0 +1,25 @@ +error[E0432]: unresolved import `crate::D::B` + --> $DIR/bad-import-with-rename.rs:7:9 + | +LL | use crate::D::B as _; + | ^^^^^^^^^^^^^^^^ no `B` in `D` + | +help: consider importing this type alias instead + | +LL | use A::B as _; + | ~~~~~~~~~~ + +error[E0432]: unresolved import `crate::D::B2` + --> $DIR/bad-import-with-rename.rs:10:9 + | +LL | use crate::D::B2; + | ^^^^^^^^^^^^ no `B2` in `D` + | +help: consider importing this type alias instead + | +LL | use A::B2; + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr index 0c16ecd4c86..a45c5bd4588 100644 --- a/src/test/ui/test-attrs/inaccessible-test-modules.stderr +++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr @@ -2,10 +2,7 @@ error[E0432]: unresolved import `main` --> $DIR/inaccessible-test-modules.rs:5:5 | LL | use main as x; - | ----^^^^^ - | | - | no `main` in the root - | help: a similar name exists in the module: `main` + | ^^^^^^^^^ no `main` in the root error[E0432]: unresolved import `test` --> $DIR/inaccessible-test-modules.rs:6:5 @@ -13,14 +10,10 @@ error[E0432]: unresolved import `test` LL | use test as y; | ^^^^^^^^^ no `test` in the root | -help: a similar name exists in the module - | -LL | use test as y; - | ~~~~ help: consider importing this module instead | -LL | use test::test; - | ~~~~~~~~~~~ +LL | use test::test as y; + | ~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs index a3bb76d7e3b..5449f5f00d5 100644 --- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs +++ b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs @@ -1,28 +1,69 @@ -// known-bug +// check-pass + +// This test checks that we're correctly dealing with inductive cycles +// with canonical inference variables. -// This should compile but fails with the current solver. -// -// This checks that the new solver uses `Ambiguous` when hitting the -// inductive cycle here when proving `exists<^0, ^1> (): Trait<^0, ^1>` -// which requires proving `Trait` but that has the same -// canonical representation. trait Trait {} -impl Trait for () +trait IsNotU32 {} +impl IsNotU32 for i32 {} +impl Trait for () // impl 1 where - (): Trait, - T: OtherTrait, + (): Trait {} -trait OtherTrait {} -impl OtherTrait for u32 {} +impl Trait for () {} // impl 2 -fn require_trait() +// If we now check whether `(): Trait` holds this has to +// result in ambiguity as both `for (): Trait` and `(): Trait` +// applies. The remainder of this test asserts that. + +// If we were to error on inductive cycles with canonical inference variables +// this would be wrong: + +// (): Trait +// - impl 1 +// - ?0: IsNotU32 // ambig +// - (): Trait // canonical cycle -> err +// - ERR +// - impl 2 +// - OK ?0 == u32 +// +// Result: OK ?0 == u32. + +// (): Trait +// - impl 1 +// - i32: IsNotU32 // ok +// - (): Trait +// - impl 1 +// - u32: IsNotU32 // err +// - ERR +// - impl 2 +// - OK +// - OK +// - impl 2 (trivial ERR) +// +// Result OK + +// This would mean that `(): Trait` is not complete, +// which is unsound if we're in coherence. + +fn implements_trait() -> (T, U) where - (): Trait -{} + (): Trait, +{ + todo!() +} + +// A hack to only constrain the infer vars after first checking +// the `(): Trait<_, _>`. +trait Constrain {} +impl Constrain for T {} +fn constrain, U>(_: U) {} fn main() { - require_trait::<_, _>(); - //~^ ERROR overflow evaluating + let (x, y) = implements_trait::<_, _>(); + + constrain::(x); + constrain::(y); } diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr deleted file mode 100644 index e4b84e07822..00000000000 --- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0275]: overflow evaluating the requirement `_: Sized` - --> $DIR/inductive-canonical-cycle.rs:26:5 - | -LL | require_trait::<_, _>(); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_canonical_cycle`) -note: required for `()` to implement `Trait<_, _>` - --> $DIR/inductive-canonical-cycle.rs:11:12 - | -LL | impl Trait for () - | ^^^^^^^^^^^ ^^ - = note: 128 redundant requirements hidden - = note: required for `()` to implement `Trait<_, _>` -note: required by a bound in `require_trait` - --> $DIR/inductive-canonical-cycle.rs:22:9 - | -LL | fn require_trait() - | ------------- required by a bound in this -LL | where -LL | (): Trait - | ^^^^^^^^^^^ required by this bound in `require_trait` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0275`. diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index e51bfa3798f..37f66d0033f 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -185,7 +185,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host // builds. - cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); + cmd.env("RUSTC", fs::canonicalize(find_miri()).unwrap()); cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! // Set rustdoc to us as well, so we can run doctests. diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index b35f7370d68..e01bfbc74d9 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -108,7 +108,8 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic - MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer + MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings + MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file ;; diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ee75e7a2932..cf6d9c28080 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -4f4d0586ad20c66a16d547581ca379beafece93a +c54c8cbac882e149e04a9e1f2d146fd548ae30ae diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 5f132bf11a9..2cc8f035466 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -88,11 +88,7 @@ impl fmt::Display for InvalidationCause { match self { InvalidationCause::Access(kind) => write!(f, "{kind}"), InvalidationCause::Retag(perm, kind) => - if *kind == RetagCause::FnEntry { - write!(f, "{perm:?} FnEntry retag") - } else { - write!(f, "{perm:?} retag") - }, + write!(f, "{perm:?} {retag}", retag = kind.summary()), } } } @@ -193,7 +189,7 @@ struct RetagOp { #[derive(Debug, Clone, Copy, PartialEq)] pub enum RetagCause { Normal, - FnReturn, + FnReturnPlace, FnEntry, TwoPhase, } @@ -495,8 +491,8 @@ impl RetagCause { fn summary(&self) -> String { match self { RetagCause::Normal => "retag", - RetagCause::FnEntry => "FnEntry retag", - RetagCause::FnReturn => "FnReturn retag", + RetagCause::FnEntry => "function-entry retag", + RetagCause::FnReturnPlace => "return-place retag", RetagCause::TwoPhase => "two-phase retag", } .to_string() diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index bcdf2e75179..ec555ba2895 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -998,7 +998,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { access: Some(AccessKind::Write), protector: Some(ProtectorKind::StrongProtector), }; - let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturn)?; + let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturnPlace)?; // And use reborrowed pointer for return place. let return_place = this.ref_to_mplace(&val)?; this.frame_mut().return_place = return_place.into(); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c11c6104c28..527d31d1f0a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -943,7 +943,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { link_name: Symbol, ) -> InterpResult<'tcx, ()> { self.check_abi(abi, exp_abi)?; - if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + // If compiler-builtins is providing the symbol, then don't treat it as a clash. + // We'll use our built-in implementation in `emulate_foreign_item_by_name` for increased + // performance. Note that this means we won't catch any undefined behavior in + // compiler-builtins when running other crates, but Miri can still be run on + // compiler-builtins itself (or any crate that uses it as a normal dependency) + if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) { + return Ok(()); + } + throw_machine_stop!(TerminationInfo::SymbolShimClashing { link_name, span: body.span.data(), diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/range_map.rs index c8ff06a3665..62198061827 100644 --- a/src/tools/miri/src/range_map.rs +++ b/src/tools/miri/src/range_map.rs @@ -219,7 +219,6 @@ mod tests { /// Query the map at every offset in the range and collect the results. fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) - .into_iter() .map(|i| { map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap() }) diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index e049eec57a3..ce24b23ca32 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -166,7 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); Scalar::from_u32(windows_check_buffer_size( - this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?, + this.write_os_str_to_wide_str( + &var, buf_ptr, buf_size, /*truncate*/ false, + )?, )) } None => { @@ -366,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match env::current_dir() { Ok(cwd) => return Ok(Scalar::from_u32(windows_check_buffer_size( - this.write_path_to_wide_str(&cwd, buf, size)?, + this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?, ))), Err(e) => this.set_last_error_from_io_error(e.kind())?, } diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 0375a228a21..f010d4251f4 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { self.eval_context_mut().write_c_str(bytes, ptr, size) } - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what - /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does include the null terminator. Length is measured in units of - /// `u16.` + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the + /// Windows APIs usually handle. + /// + /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false, + /// length))` without trying to write if `size` is not large enough to fit the contents of + /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process + /// was successful. The string length returned does include the null terminator. Length is + /// measured in units of `u16.` + /// + /// If `truncate == true`, then in case `size` is not large enough it *will* write the first + /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`). fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, ptr: Pointer>, size: u64, + truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { @@ -129,7 +135,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } let u16_vec = os_str_to_u16vec(os_str)?; - self.eval_context_mut().write_wide_str(&u16_vec, ptr, size) + let (written, size_needed) = self.eval_context_mut().write_wide_str(&u16_vec, ptr, size)?; + if truncate && !written && size > 0 { + // Write the truncated part that fits. + let truncated_data = &u16_vec[..size.saturating_sub(1).try_into().unwrap()]; + let (written, written_len) = + self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?; + assert!(written && written_len == size); + } + Ok((written, size_needed)) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. @@ -143,7 +157,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; - assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); + let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + assert!(written); Ok(arg_place.ptr) } @@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; - assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); + let (written, _) = + self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap(); + assert!(written); Ok(arg_place.ptr) } @@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { path: &Path, ptr: Pointer>, size: u64, + truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, ptr, size) + this.write_os_str_to_wide_str(&os_str, ptr, size, truncate) } /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, @@ -232,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.alloc_os_str_as_c_str(&os_str, memkind) } + /// Allocate enough memory to store a Path as a null-terminated sequence of `u16`s, + /// adjusting path separators if needed. + fn alloc_path_as_wide_str( + &mut self, + path: &Path, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + let os_str = + this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.alloc_os_str_as_wide_str(&os_str, memkind) + } + #[allow(clippy::get_first)] fn convert_path<'a>( &self, diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 1da8f7c0e3e..f310d16e861 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -381,6 +381,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_u32(1), dest)?; } + "GetModuleFileNameW" => { + let [handle, filename, size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + this.check_no_isolation("`GetModuleFileNameW`")?; + + let handle = this.read_machine_usize(handle)?; + let filename = this.read_pointer(filename)?; + let size = this.read_scalar(size)?.to_u32()?; + + if handle != 0 { + throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle"); + } + + // Using the host current_exe is a bit off, but consistent with Linux + // (where stdlib reads /proc/self/exe). + // Unfortunately this Windows function has a crazy behavior so we can't just use + // `write_path_to_wide_str`... + let path = std::env::current_exe().unwrap(); + let (all_written, size_needed) = this.write_path_to_wide_str( + &path, + filename, + size.into(), + /*truncate*/ true, + )?; + + if all_written { + // If the function succeeds, the return value is the length of the string that + // is copied to the buffer, in characters, not including the terminating null + // character. + this.write_int(size_needed.checked_sub(1).unwrap(), dest)?; + } else { + // If the buffer is too small to hold the module name, the string is truncated + // to nSize characters including the terminating null character, the function + // returns nSize, and the function sets the last error to + // ERROR_INSUFFICIENT_BUFFER. + this.write_int(size, dest)?; + let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER"); + this.set_last_error(insufficient_buffer)?; + } + } // Threading "CreateThread" => { diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index bf7f0411bed..a84ed859763 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -14,6 +14,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + [[package]] name = "bytes" version = "1.3.0" @@ -44,8 +50,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -57,6 +65,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.139" @@ -123,6 +140,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + [[package]] name = "page_size" version = "0.5.0" @@ -269,9 +292,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" dependencies = [ "autocfg", "bytes", @@ -316,6 +339,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + [[package]] name = "winapi" version = "0.3.9" diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index 1df35bbbe2f..f5ab6acf008 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -13,11 +13,11 @@ libc = "0.2" num_cpus = "1.10.1" getrandom_1 = { package = "getrandom", version = "0.1" } -getrandom = { version = "0.2" } +getrandom = { version = "0.2", features = ["js"] } rand = { version = "0.8", features = ["small_rng"] } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies] page_size = "0.5" -tokio = { version = "1.0", features = ["full"] } +tokio = { version = "1.23", features = ["full"] } [workspace] diff --git a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr index 55aaed62f4f..ae54d0248dc 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -5,7 +5,7 @@ LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^ | | | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] + | this error occurs as part of function-entry retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | safe_raw(xraw, xshr); | ^^^^ -help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call +help: was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call --> $DIR/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr index e3bffde1f01..236c8fb0187 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let z = &mut x as *mut i32; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call +help: was later invalidated at offsets [0x0..0x4] by a Unique function-entry retag inside this call --> $DIR/fnentry_invalidation.rs:LL:CC | LL | x.do_bad(); diff --git a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr index b104de4b8d9..45c2197050a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation2.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0xc] | LL | let ptr = t.sli.as_ptr(); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag inside this call +help: was later invalidated at offsets [0x0..0xc] by a Unique function-entry retag inside this call --> $DIR/fnentry_invalidation2.rs:LL:CC | LL | let _ = t.sli.as_mut_ptr(); diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs index 04e89ec361b..7ccafec6037 100644 --- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs @@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() { } } +fn dtors_in_dtors_in_dtors() { + use std::cell::UnsafeCell; + use std::sync::{Arc, Condvar, Mutex}; + + #[derive(Clone, Default)] + struct Signal(Arc<(Mutex, Condvar)>); + + impl Signal { + fn notify(&self) { + let (set, cvar) = &*self.0; + *set.lock().unwrap() = true; + cvar.notify_one(); + } + + fn wait(&self) { + let (set, cvar) = &*self.0; + let mut set = set.lock().unwrap(); + while !*set { + set = cvar.wait(set).unwrap(); + } + } + } + + struct NotifyOnDrop(Signal); + + impl Drop for NotifyOnDrop { + fn drop(&mut self) { + let NotifyOnDrop(ref f) = *self; + f.notify(); + } + } + + struct S1(Signal); + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); + + impl Drop for S1 { + fn drop(&mut self) { + let S1(ref signal) = *self; + unsafe { + let _ = K2.try_with(|s| *s.get() = Some(NotifyOnDrop(signal.clone()))); + } + } + } + + let signal = Signal::default(); + let signal2 = signal.clone(); + let _t = thread::spawn(move || unsafe { + let mut signal = Some(signal2); + K1.with(|s| *s.get() = Some(S1(signal.take().unwrap()))); + }); + // Note that this test will deadlock if TLS destructors aren't run (this + // requires the destructor to be run to pass the test). + signal.wait(); +} + fn main() { check_destructors(); check_blocking(); join_orders_after_tls_destructors(); + dtors_in_dtors_in_dtors(); } diff --git a/src/tools/miri/tests/pass/shims/env/current_exe.rs b/src/tools/miri/tests/pass/shims/env/current_exe.rs index 3f1153d265d..898a42b72d1 100644 --- a/src/tools/miri/tests/pass/shims/env/current_exe.rs +++ b/src/tools/miri/tests/pass/shims/env/current_exe.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: current_exe not supported on Windows //@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target //@compile-flags: -Zmiri-disable-isolation use std::env;