diff --git a/RELEASES.md b/RELEASES.md
index 6aba476103e7f..29c872eb44896 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -112,6 +112,14 @@ tools.
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
+Version 1.80.1 (2024-08-08)
+===========================
+
+
+
+- [Fix miscompilation in the jump threading MIR optimization when comparing floats](https://github.com/rust-lang/rust/pull/128271)
+- [Revert changes to the `dead_code` lint from 1.80.0](https://github.com/rust-lang/rust/pull/128618)
+
Version 1.80.0 (2024-07-25)
==========================
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e49ae60e890ba..cb2fa6e9d746b 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -61,7 +61,6 @@ use rustc_session::lint::{Lint, LintId};
use rustc_session::output::collect_crate_types;
use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
use rustc_span::source_map::FileLoader;
-use rustc_span::symbol::sym;
use rustc_span::FileName;
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTriple};
@@ -777,16 +776,8 @@ fn print_crate_info(
.config
.iter()
.filter_map(|&(name, value)| {
- // Note that crt-static is a specially recognized cfg
- // directive that's printed out here as part of
- // rust-lang/rust#37406, but in general the
- // `target_feature` cfg is gated under
- // rust-lang/rust#29717. For now this is just
- // specifically allowing the crt-static cfg and that's
- // it, this is intended to get into Cargo and then go
- // through to build scripts.
- if (name != sym::target_feature || value != Some(sym::crt_dash_static))
- && !sess.is_nightly_build()
+ // On stable, exclude unstable flags.
+ if !sess.is_nightly_build()
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
{
return None;
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 7be45463f1512..149bc6d26984d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
return;
};
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
- if sugg.is_empty() {
- return;
- };
diag.multipart_suggestion(
format!(
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
@@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0`
// and suggest `Trait0`.
+ // Functions are found in three different contexts.
+ // 1. Independent functions
+ // 2. Functions inside trait blocks
+ // 3. Functions inside impl blocks
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
(sig, generics, None)
@@ -180,6 +181,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
owner_id,
..
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
+ hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(sig, _),
+ generics,
+ owner_id,
+ ..
+ }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
_ => return false,
};
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
@@ -187,6 +194,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
let mut is_downgradable = true;
+
+ // Check if trait object is safe for suggesting dynamic dispatch.
let is_object_safe = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
@@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
_ => false,
};
+
+ let borrowed = matches!(
+ tcx.parent_hir_node(self_ty.hir_id),
+ hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
+ );
+
+ // Suggestions for function return type.
if let hir::FnRetTy::Return(ty) = sig.decl.output
- && ty.hir_id == self_ty.hir_id
+ && ty.peel_refs().hir_id == self_ty.hir_id
{
let pre = if !is_object_safe {
format!("`{trait_name}` is not object safe, ")
@@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
single underlying type",
);
+
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
+
+ // Suggest `Box` for return type
if is_object_safe {
- diag.multipart_suggestion_verbose(
- "alternatively, you can return an owned trait object",
+ // If the return type is `&Trait`, we don't want
+ // the ampersand to be displayed in the `Box`
+ // suggestion.
+ let suggestion = if borrowed {
+ vec![(ty.span, format!("Box"))]
+ } else {
vec![
(ty.span.shrink_to_lo(), "Box".to_string()),
- ],
+ ]
+ };
+
+ diag.multipart_suggestion_verbose(
+ "alternatively, you can return an owned trait object",
+ suggestion,
Applicability::MachineApplicable,
);
} else if is_downgradable {
@@ -230,24 +258,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
return true;
}
+
+ // Suggestions for function parameters.
for ty in sig.decl.inputs {
- if ty.hir_id != self_ty.hir_id {
+ if ty.peel_refs().hir_id != self_ty.hir_id {
continue;
}
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
- if !sugg.is_empty() {
- diag.multipart_suggestion_verbose(
- format!("use a new generic type parameter, constrained by `{trait_name}`"),
- sugg,
- Applicability::MachineApplicable,
- );
- diag.multipart_suggestion_verbose(
- "you can also use an opaque type, but users won't be able to specify the type \
- parameter when calling the `fn`, having to rely exclusively on type inference",
- impl_sugg,
- Applicability::MachineApplicable,
- );
- }
+ diag.multipart_suggestion_verbose(
+ format!("use a new generic type parameter, constrained by `{trait_name}`"),
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ diag.multipart_suggestion_verbose(
+ "you can also use an opaque type, but users won't be able to specify the type \
+ parameter when calling the `fn`, having to rely exclusively on type inference",
+ impl_sugg,
+ Applicability::MachineApplicable,
+ );
if !is_object_safe {
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
if is_downgradable {
@@ -255,14 +283,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
diag.downgrade_to_delayed_bug();
}
} else {
+ // No ampersand in suggestion if it's borrowed already
+ let (dyn_str, paren_dyn_str) =
+ if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
+
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
// There are more than one trait bound, we need surrounding parentheses.
vec![
- (self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
+ (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
(self_ty.span.shrink_to_hi(), ")".to_string()),
]
} else {
- vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
+ vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
};
diag.multipart_suggestion_verbose(
format!(
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 7b90191503702..081a23b6ff317 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -3,8 +3,6 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
use std::borrow::Cow;
-use std::cell::RefCell;
-use std::collections::hash_map::Entry;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Index, IndexMut};
use std::{iter, mem};
@@ -26,7 +24,6 @@ use rustc_index::bit_set::BitSet;
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_serialize::{Decodable, Encodable};
-use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
@@ -106,65 +103,6 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
}
}
-thread_local! {
- static PASS_NAMES: RefCell> = {
- RefCell::new(FxHashMap::default())
- };
-}
-
-/// Converts a MIR pass name into a snake case form to match the profiling naming style.
-fn to_profiler_name(type_name: &'static str) -> &'static str {
- PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
- Entry::Occupied(e) => *e.get(),
- Entry::Vacant(e) => {
- let snake_case: String = type_name
- .chars()
- .flat_map(|c| {
- if c.is_ascii_uppercase() {
- vec!['_', c.to_ascii_lowercase()]
- } else if c == '-' {
- vec!['_']
- } else {
- vec![c]
- }
- })
- .collect();
- let result = &*String::leak(format!("mir_pass{}", snake_case));
- e.insert(result);
- result
- }
- })
-}
-
-/// A streamlined trait that you can implement to create a pass; the
-/// pass will be named after the type, and it will consist of a main
-/// loop that goes over each available MIR and applies `run_pass`.
-pub trait MirPass<'tcx> {
- fn name(&self) -> &'static str {
- // FIXME Simplify the implementation once more `str` methods get const-stable.
- // See copypaste in `MirLint`
- const {
- let name = std::any::type_name::();
- crate::util::common::c_name(name)
- }
- }
-
- fn profiler_name(&self) -> &'static str {
- to_profiler_name(self.name())
- }
-
- /// Returns `true` if this pass is enabled with the current combination of compiler flags.
- fn is_enabled(&self, _sess: &Session) -> bool {
- true
- }
-
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
-
- fn is_mir_dump_enabled(&self) -> bool {
- true
- }
-}
-
impl MirPhase {
/// Gets the index of the current MirPhase within the set of all `MirPhase`s.
///
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 9906be60e3e95..a98e6943d68ee 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -612,7 +612,9 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
let def_id = body.source.def_id();
let kind = tcx.def_kind(def_id);
let is_function = match kind {
- DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+ DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::SyntheticCoroutineBody => {
+ true
+ }
_ => tcx.is_closure_like(def_id),
};
match (kind, body.source.promoted) {
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 698104b0462e3..dd00db8635f4d 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
adt: ty::AdtDef<'_>,
) -> InhabitedPredicate<'tcx> {
debug_assert!(!adt.is_union());
- if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
- // Non-exhaustive variants from other crates are always considered inhabited.
- return InhabitedPredicate::True;
- }
InhabitedPredicate::all(
tcx,
self.fields.iter().map(|field| {
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index 2038d3f84484e..223b2b3bfe4de 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -20,19 +20,3 @@ pub fn to_readable_str(mut val: usize) -> String {
groups.join("_")
}
-
-// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
-pub const fn c_name(name: &'static str) -> &'static str {
- // FIXME Simplify the implementation once more `str` methods get const-stable.
- // and inline into call site
- let bytes = name.as_bytes();
- let mut i = bytes.len();
- while i > 0 && bytes[i - 1] != b':' {
- i = i - 1;
- }
- let (_, bytes) = bytes.split_at(i);
- match std::str::from_utf8(bytes) {
- Ok(name) => name,
- Err(_) => name,
- }
-}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 0171cc8591809..8c3e6f49b1618 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,7 +1,7 @@
use rustc_ast::MetaItem;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, Body, Local, Location, MirPass};
+use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
@@ -18,8 +18,6 @@ use crate::impls::{
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
-pub struct SanityCheck;
-
fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option {
for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
let items = attr.meta_item_list();
@@ -33,53 +31,50 @@ fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option MirPass<'tcx> for SanityCheck {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let def_id = body.source.def_id();
- if !tcx.has_attr(def_id, sym::rustc_mir) {
- debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
- return;
- } else {
- debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
- }
+pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+ let def_id = body.source.def_id();
+ if !tcx.has_attr(def_id, sym::rustc_mir) {
+ debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
+ return;
+ } else {
+ debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
+ }
- let param_env = tcx.param_env(def_id);
- let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
+ let param_env = tcx.param_env(def_id);
+ let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
- if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
- let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
+ if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
+ let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
+ .into_engine(tcx, body)
+ .iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
- }
+ sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
+ }
- if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
- let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
+ if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
+ let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
+ .into_engine(tcx, body)
+ .iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
- }
+ sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
+ }
- if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
- let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
+ if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
+ let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
+ .into_engine(tcx, body)
+ .iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
- }
+ sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
+ }
- if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
- let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
+ if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
+ let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
- sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
- }
+ sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
+ }
- if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
- tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
- }
+ if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
+ tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
}
}
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index edb6bc4fbea2f..e4bc6b3efe422 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -22,7 +22,7 @@ use rustc_target::spec::PanicStrategy;
#[derive(PartialEq)]
pub struct AbortUnwindingCalls;
-impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
+impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
let kind = tcx.def_kind(def_id);
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index df5312d155c13..78e850de3c772 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -30,7 +30,7 @@ pub use self::AddCallGuards::*;
*
*/
-impl<'tcx> MirPass<'tcx> for AddCallGuards {
+impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
self.add_call_guards(body);
}
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index e503119a3495b..4a8196aeff5b0 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -37,7 +37,7 @@ use crate::util;
/// blowup.
pub struct AddMovesForPackedDrops;
-impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
+impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
add_moves_for_packed_drops(tcx, body);
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 79bc21cab147e..2e12064fe7351 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -48,7 +48,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b
}
}
-impl<'tcx> MirPass<'tcx> for AddRetag {
+impl<'tcx> crate::MirPass<'tcx> for AddRetag {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.opts.unstable_opts.mir_emit_retag
}
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index 04204c68f7b76..369f6c6008440 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -62,7 +62,7 @@ pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
checker.patcher.apply(body);
}
-impl<'tcx> MirPass<'tcx> for Subtyper {
+impl<'tcx> crate::MirPass<'tcx> for Subtyper {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
subtype_finder(tcx, body);
}
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index ad362f22ce197..2e072aa262aac 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -9,7 +9,7 @@ use tracing::{debug, trace};
pub struct CheckAlignment;
-impl<'tcx> MirPass<'tcx> for CheckAlignment {
+impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
fn is_enabled(&self, sess: &Session) -> bool {
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
if sess.target.llvm_target == "i686-pc-windows-msvc" {
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 1f615c9d8d1a2..fb03323e37e6e 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -6,11 +6,11 @@ use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;
use rustc_span::Span;
-use crate::{errors, MirLint};
+use crate::errors;
pub struct CheckConstItemMutation;
-impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
+impl<'tcx> crate::MirLint<'tcx> for CheckConstItemMutation {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
checker.visit_body(body);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index eb76a39be57ff..2f957de7e78d8 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -3,11 +3,11 @@ use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, TyCtxt};
-use crate::{errors, util, MirLint};
+use crate::{errors, util};
pub struct CheckPackedRef;
-impl<'tcx> MirLint<'tcx> for CheckPackedRef {
+impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let source_info = SourceInfo::outermost(body.span);
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 08c9f9f08e6b2..2f3be1e425d8d 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -21,11 +21,9 @@ use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, Termi
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::TyCtxt;
-use crate::MirPass;
-
pub struct CleanupPostBorrowck;
-impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
+impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
for basic_block in body.basic_blocks.as_mut() {
for statement in basic_block.statements.iter_mut() {
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 5c267f853783f..85d25ca22318d 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -19,7 +19,7 @@ use crate::ssa::SsaLocals;
/// We want to replace all those locals by `_a`, either copied or moved.
pub struct CopyProp;
-impl<'tcx> MirPass<'tcx> for CopyProp {
+impl<'tcx> crate::MirPass<'tcx> for CopyProp {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 1
}
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 80ba1c4266811..eefb748e49d51 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1535,7 +1535,7 @@ fn check_field_tys_sized<'tcx>(
}
}
-impl<'tcx> MirPass<'tcx> for StateTransform {
+impl<'tcx> crate::MirPass<'tcx> for StateTransform {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let Some(old_yield_ty) = body.yield_ty() else {
// This only applies to coroutines
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index ebe8d2eff4ff3..cf39c136b01a3 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -207,11 +207,12 @@ pub fn coroutine_by_move_body_def_id<'tcx>(
let mut by_move_body = body.clone();
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
- dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
- let body_def = tcx.create_def(coroutine_def_id, kw::Empty, DefKind::SyntheticCoroutineBody);
+ // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`.
+ let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody);
by_move_body.source =
mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id()));
+ dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(()));
// Inherited from the by-ref coroutine.
body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone());
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index bba354d29363d..4edba61fdec9e 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -28,14 +28,13 @@ use tracing::{debug, debug_span, instrument, trace};
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
use crate::coverage::graph::CoverageGraph;
use crate::coverage::mappings::ExtractedMappings;
-use crate::MirPass;
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
/// to construct the coverage map.
pub struct InstrumentCoverage;
-impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.instrument_coverage()
}
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index bf522fd5ef4ec..ea473b64ce540 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -8,11 +8,9 @@ use rustc_middle::mir::{
use rustc_middle::ty::TyCtxt;
use tracing::instrument;
-use crate::MirPass;
-
pub struct CtfeLimit;
-impl<'tcx> MirPass<'tcx> for CtfeLimit {
+impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
#[instrument(skip(self, _tcx, body))]
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let doms = body.basic_blocks.dominators();
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index b16d25c93bb96..46f7408ef8064 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -28,7 +28,7 @@ const PLACE_LIMIT: usize = 100;
pub struct DataflowConstProp;
-impl<'tcx> MirPass<'tcx> for DataflowConstProp {
+impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 3
}
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 39c8db184a5a2..9081a2e2e3028 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -132,7 +132,7 @@ pub enum DeadStoreElimination {
Final,
}
-impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
+impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
fn name(&self) -> &'static str {
match self {
DeadStoreElimination::Initial => "DeadStoreElimination-initial",
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index b38f4a4a823b1..be50c1da8a438 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -15,7 +15,7 @@ use super::simplify::simplify_cfg;
pub struct DeduplicateBlocks;
-impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
}
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 0e2fccc85dacd..a878f777448f5 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -78,7 +78,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
checker.patcher.apply(body);
}
-impl<'tcx> MirPass<'tcx> for Derefer {
+impl<'tcx> crate::MirPass<'tcx> for Derefer {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
deref_finder(tcx, body);
}
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index a6d626d3f8ff5..8940a21d7fae5 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -146,11 +146,9 @@ use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex
use rustc_mir_dataflow::Analysis;
use tracing::{debug, trace};
-use crate::MirPass;
-
pub struct DestinationPropagation;
-impl<'tcx> MirPass<'tcx> for DestinationPropagation {
+impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// For now, only run at MIR opt level 3. Two things need to be changed before this can be
// turned on by default:
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 29db45f94506f..06ae1b490d75c 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -7,11 +7,9 @@ use rustc_middle::mir::{write_mir_pretty, Body};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutFileName, OutputType};
-use crate::MirPass;
-
pub struct Marker(pub &'static str);
-impl<'tcx> MirPass<'tcx> for Marker {
+impl<'tcx> crate::MirPass<'tcx> for Marker {
fn name(&self) -> &'static str {
self.0
}
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 67b81efd61475..1c54cd70023d6 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -92,7 +92,7 @@ use super::simplify::simplify_cfg;
/// ```
pub struct EarlyOtherwiseBranch;
-impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
+impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index e5778f8a05d2e..5dd82f40163da 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -88,7 +88,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
pub struct ElaborateBoxDerefs;
-impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if let Some(def_id) = tcx.lang_items().owned_box() {
let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index d0809d9388def..f4a951ebde600 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -49,7 +49,7 @@ use crate::deref_separator::deref_finder;
/// ```
pub struct ElaborateDrops;
-impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
#[instrument(level = "trace", skip(self, tcx, body))]
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index b7873e73c18c7..199fd0f10ee2c 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -9,11 +9,11 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
-use crate::{errors, MirLint};
+use crate::errors;
pub struct FunctionItemReferences;
-impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+impl<'tcx> crate::MirLint<'tcx> for FunctionItemReferences {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = FunctionItemRefChecker { tcx, body };
checker.visit_body(body);
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index fb9baeeb3ed88..df0fcc42e5926 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -111,7 +111,7 @@ use crate::ssa::{AssignedValue, SsaLocals};
pub struct GVN;
-impl<'tcx> MirPass<'tcx> for GVN {
+impl<'tcx> crate::MirPass<'tcx> for GVN {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 4482801826ab0..6cc7e0ee1e4bc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -42,7 +42,7 @@ struct CallSite<'tcx> {
source_info: SourceInfo,
}
-impl<'tcx> MirPass<'tcx> for Inline {
+impl<'tcx> crate::MirPass<'tcx> for Inline {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
// MIR correctly when Modified Condition/Decision Coverage is enabled.
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 3ec553d0ba0c5..4fbfa744e6733 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -27,7 +27,7 @@ impl InstSimplify {
}
}
-impl<'tcx> MirPass<'tcx> for InstSimplify {
+impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
fn name(&self) -> &'static str {
self.name()
}
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 435b6a0116348..02dd56e1b4fdb 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -61,7 +61,7 @@ const MAX_BACKTRACK: usize = 5;
const MAX_COST: usize = 100;
const MAX_PLACES: usize = 100;
-impl<'tcx> MirPass<'tcx> for JumpThreading {
+impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 15d71ee2ac81f..61405fb25c6f2 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -25,11 +25,10 @@ use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, Va
use tracing::{debug, instrument, trace};
use crate::errors::{AssertLint, AssertLintKind};
-use crate::MirLint;
pub struct KnownPanicsLint;
-impl<'tcx> MirLint<'tcx> for KnownPanicsLint {
+impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
if body.tainted_by_errors.is_some() {
return;
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index cbc3169f2f10a..f02ba71ddc64c 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -27,7 +27,7 @@ pub struct EnumSizeOpt {
pub(crate) discrepancy: u64,
}
-impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
+impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
fn is_enabled(&self, sess: &Session) -> bool {
// There are some differences in behavior on wasm and ARM that are not properly
// understood, so we conservatively treat this optimization as unsound:
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9e460a725eeb2..62e73ba2c8e24 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -26,13 +26,12 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_index::IndexVec;
use rustc_middle::mir::{
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
- MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
+ MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
Statement, StatementKind, TerminatorKind, START_BLOCK,
};
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_middle::util::Providers;
use rustc_middle::{bug, query, span_bug};
-use rustc_mir_dataflow::rustc_peek;
use rustc_span::source_map::Spanned;
use rustc_span::{sym, DUMMY_SP};
use rustc_trait_selection::traits;
@@ -41,7 +40,7 @@ use tracing::{debug, trace};
#[macro_use]
mod pass_manager;
-use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
mod abort_unwinding_calls;
mod add_call_guards;
@@ -96,6 +95,7 @@ mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
mod reveal_all;
+mod sanity_check;
mod shim;
mod ssa;
// This pass is public to allow external drivers to perform MIR cleanup
@@ -288,7 +288,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> {
&Lint(function_item_references::FunctionItemReferences),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::Initial,
- &rustc_peek::SanityCheck, // Just a lint
+ &Lint(sanity_check::SanityCheck),
],
None,
);
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index a9bdff95fe5ac..55eec33230615 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -9,7 +9,7 @@ use crate::take_array;
pub struct LowerIntrinsics;
-impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
+impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let local_decls = &body.local_decls;
for block in body.basic_blocks.as_mut() {
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 77a7f4f47dd4e..555309a775001 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
pub struct LowerSliceLenCalls;
-impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 5240f1c887c5c..233b39fb47a41 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
pub struct MatchBranchSimplification;
-impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 1
}
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index 32c8064ebca50..41ce03caf0873 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -1,5 +1,5 @@
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
+use rustc_middle::mir::{self, Location, MentionedItem};
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
@@ -13,7 +13,7 @@ struct MentionedItemsVisitor<'a, 'tcx> {
mentioned_items: &'a mut Vec>>,
}
-impl<'tcx> MirPass<'tcx> for MentionedItems {
+impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
fn is_enabled(&self, _sess: &Session) -> bool {
// If this pass is skipped the collector assume that nothing got mentioned! We could
// potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index 1e87a0e01d9be..1b4972d487eea 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -9,7 +9,7 @@ use crate::simplify;
pub struct MultipleReturnTerminators;
-impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
+impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
}
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index dd1875f2a78ac..94573a9d89bfd 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -8,8 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
use rustc_middle::ty::TyCtxt;
use tracing::{debug, trace};
-use crate::MirPass;
-
/// This pass looks for MIR that always copies the same local into the return place and eliminates
/// the copy by renaming all uses of that local to `_0`.
///
@@ -34,7 +32,7 @@ use crate::MirPass;
/// [#71003]: https://github.com/rust-lang/rust/pull/71003
pub struct RenameReturnPlace;
-impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
+impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// unsound: #111005
sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 51e2760040478..28d4e1a1c9184 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -1,19 +1,99 @@
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use tracing::trace;
use crate::lint::lint_body;
-use crate::{validate, MirPass};
+use crate::validate;
+
+thread_local! {
+ static PASS_NAMES: RefCell> = {
+ RefCell::new(FxHashMap::default())
+ };
+}
+
+/// Converts a MIR pass name into a snake case form to match the profiling naming style.
+fn to_profiler_name(type_name: &'static str) -> &'static str {
+ PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
+ Entry::Occupied(e) => *e.get(),
+ Entry::Vacant(e) => {
+ let snake_case: String = type_name
+ .chars()
+ .flat_map(|c| {
+ if c.is_ascii_uppercase() {
+ vec!['_', c.to_ascii_lowercase()]
+ } else if c == '-' {
+ vec!['_']
+ } else {
+ vec![c]
+ }
+ })
+ .collect();
+ let result = &*String::leak(format!("mir_pass{}", snake_case));
+ e.insert(result);
+ result
+ }
+ })
+}
+
+// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
+const fn c_name(name: &'static str) -> &'static str {
+ // FIXME Simplify the implementation once more `str` methods get const-stable.
+ // and inline into call site
+ let bytes = name.as_bytes();
+ let mut i = bytes.len();
+ while i > 0 && bytes[i - 1] != b':' {
+ i = i - 1;
+ }
+ let (_, bytes) = bytes.split_at(i);
+ match std::str::from_utf8(bytes) {
+ Ok(name) => name,
+ Err(_) => name,
+ }
+}
+
+/// A streamlined trait that you can implement to create a pass; the
+/// pass will be named after the type, and it will consist of a main
+/// loop that goes over each available MIR and applies `run_pass`.
+pub(super) trait MirPass<'tcx> {
+ fn name(&self) -> &'static str {
+ // FIXME Simplify the implementation once more `str` methods get const-stable.
+ // See copypaste in `MirLint`
+ const {
+ let name = std::any::type_name::();
+ c_name(name)
+ }
+ }
+
+ fn profiler_name(&self) -> &'static str {
+ to_profiler_name(self.name())
+ }
+
+ /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ true
+ }
+}
-/// Just like `MirPass`, except it cannot mutate `Body`.
-pub trait MirLint<'tcx> {
+/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
+/// disabled (via the `Lint` adapter).
+pub(super) trait MirLint<'tcx> {
fn name(&self) -> &'static str {
// FIXME Simplify the implementation once more `str` methods get const-stable.
// See copypaste in `MirPass`
const {
let name = std::any::type_name::();
- rustc_middle::util::common::c_name(name)
+ c_name(name)
}
}
@@ -26,7 +106,7 @@ pub trait MirLint<'tcx> {
/// An adapter for `MirLint`s that implements `MirPass`.
#[derive(Debug, Clone)]
-pub struct Lint(pub T);
+pub(super) struct Lint(pub T);
impl<'tcx, T> MirPass<'tcx> for Lint
where
@@ -49,7 +129,7 @@ where
}
}
-pub struct WithMinOptLevel(pub u32, pub T);
+pub(super) struct WithMinOptLevel(pub u32, pub T);
impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel
where
@@ -70,7 +150,7 @@ where
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
/// validated at the end.
-pub fn run_passes_no_validate<'tcx>(
+pub(super) fn run_passes_no_validate<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
@@ -80,7 +160,7 @@ pub fn run_passes_no_validate<'tcx>(
}
/// The optional `phase_change` is applied after executing all the passes, if present
-pub fn run_passes<'tcx>(
+pub(super) fn run_passes<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
@@ -89,7 +169,7 @@ pub fn run_passes<'tcx>(
run_passes_inner(tcx, body, passes, phase_change, true);
}
-pub fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
+pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
where
P: MirPass<'tcx> + ?Sized,
{
@@ -185,11 +265,11 @@ fn run_passes_inner<'tcx>(
}
}
-pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
}
-pub fn dump_mir_for_pass<'tcx>(
+pub(super) fn dump_mir_for_pass<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pass_name: &str,
@@ -205,7 +285,7 @@ pub fn dump_mir_for_pass<'tcx>(
);
}
-pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
assert_eq!(body.pass_count, 0);
mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(()))
}
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 14dd0c6f61e76..ad71c6226601c 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -17,7 +17,7 @@ use rustc_session::Session;
/// `IndexVec`, unless that successor is a back-edge (such as from a loop).
pub struct ReorderBasicBlocks;
-impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
+impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
fn is_enabled(&self, _session: &Session) -> bool {
false
}
@@ -45,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
/// (Does not reorder arguments nor the [`RETURN_PLACE`].)
pub struct ReorderLocals;
-impl<'tcx> MirPass<'tcx> for ReorderLocals {
+impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
fn is_enabled(&self, _session: &Session) -> bool {
false
}
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 0c940bac13c0b..cf0a569ffa494 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
pub promoted_fragments: Cell>>,
}
-impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 8d0b47cb34a8f..4a447d24ccec7 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -72,7 +72,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
/// so we perform all the possible instantiations without removing the `_1 = &_2` statement.
pub struct ReferencePropagation;
-impl<'tcx> MirPass<'tcx> for ReferencePropagation {
+impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 33c7d1695c02d..ccba8d015e3a6 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -10,7 +10,7 @@ use tracing::debug;
/// terrible code for these.
pub struct RemoveNoopLandingPads;
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.panic_strategy() != PanicStrategy::Abort
}
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index 6c0b50fafdb40..5801fdedcebb2 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -6,7 +6,7 @@ use tracing::trace;
pub struct RemovePlaceMention;
-impl<'tcx> MirPass<'tcx> for RemovePlaceMention {
+impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
!sess.opts.unstable_opts.mir_keep_place_mention
}
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index af89395dddd2d..329b30d3890a3 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -6,7 +6,7 @@ use tracing::trace;
pub struct RemoveStorageMarkers;
-impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers()
}
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index fae1cb5f7d8a5..aafe971311d31 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -6,8 +6,6 @@ use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
use rustc_target::abi::FieldIdx;
-use crate::MirPass;
-
/// Removes `Drop` terminators whose target is known to be uninitialized at
/// that point.
///
@@ -18,7 +16,7 @@ use crate::MirPass;
/// [#90770]: https://github.com/rust-lang/rust/issues/90770
pub struct RemoveUninitDrops;
-impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let move_data =
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 9adcb5a38fd8b..43109aae0fb6c 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
pub struct RemoveUnneededDrops;
-impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("Running RemoveUnneededDrops on {:?}", body.source);
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 9a94cae338288..9aa46bd4fbae6 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RemoveZsts;
-impl<'tcx> MirPass<'tcx> for RemoveZsts {
+impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 5eaa024f84689..29312a99cbc01 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RevealAll;
-impl<'tcx> MirPass<'tcx> for RevealAll {
+impl<'tcx> crate::MirPass<'tcx> for RevealAll {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
diff --git a/compiler/rustc_mir_transform/src/sanity_check.rs b/compiler/rustc_mir_transform/src/sanity_check.rs
new file mode 100644
index 0000000000000..c9445d1816295
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/sanity_check.rs
@@ -0,0 +1,11 @@
+use rustc_middle::mir::Body;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::rustc_peek::sanity_check;
+
+pub(super) struct SanityCheck;
+
+impl<'tcx> crate::MirLint<'tcx> for SanityCheck {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+ sanity_check(tcx, body);
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d1c2c91e00fd7..1478b86d3c765 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -74,7 +74,7 @@ pub(crate) fn simplify_cfg(body: &mut Body<'_>) {
body.basic_blocks_mut().raw.shrink_to_fit();
}
-impl<'tcx> MirPass<'tcx> for SimplifyCfg {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
fn name(&self) -> &'static str {
self.name()
}
@@ -366,7 +366,7 @@ pub enum SimplifyLocals {
Final,
}
-impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
fn name(&self) -> &'static str {
match &self {
SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 7c8a686d0077e..5a014bb734683 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -7,7 +7,7 @@ pub enum SimplifyConstCondition {
Final,
}
/// A pass that replaces a branch with a goto when its condition is known.
-impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
fn name(&self) -> &'static str {
match self {
SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index ac892adebec1b..bd30ecc59b3d7 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -9,8 +9,6 @@ use rustc_middle::mir::{
use rustc_middle::ty::{Ty, TyCtxt};
use tracing::trace;
-use super::MirPass;
-
/// Pass to convert `if` conditions on integrals into switches on the integral.
/// For an example, it turns something like
///
@@ -27,7 +25,7 @@ use super::MirPass;
/// ```
pub struct SimplifyComparisonIntegral;
-impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 35cb6872fe9a2..64a928728307b 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::TyCtxt;
/// needed to do that too, including updating the debug info.
pub struct SingleUseConsts;
-impl<'tcx> MirPass<'tcx> for SingleUseConsts {
+impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 906e2c23f3b8c..3c5ccc0c99a8a 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -13,7 +13,7 @@ use tracing::{debug, instrument};
pub struct ScalarReplacementOfAggregates;
-impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
+impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 2427fbac5eefa..51a322628ee69 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -12,8 +12,6 @@ use rustc_middle::ty::{Ty, TyCtxt};
use rustc_target::abi::{Abi, Variants};
use tracing::trace;
-use crate::MirPass;
-
pub struct UnreachableEnumBranching;
fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option {
@@ -74,7 +72,7 @@ fn variant_discriminants<'tcx>(
}
}
-impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
+impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index a6c3c3b189ed0..b8da86f1a8dde 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -12,7 +12,7 @@ use rustc_target::abi::Size;
pub struct UnreachablePropagation;
-impl MirPass<'_> for UnreachablePropagation {
+impl crate::MirPass<'_> for UnreachablePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// Enable only under -Zmir-opt-level=2 as this can make programs less debuggable.
sess.mir_opt_level() >= 2
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 99e06f59dd04d..69e2592e82c77 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -36,7 +36,7 @@ pub struct Validator {
pub mir_phase: MirPhase,
}
-impl<'tcx> MirPass<'tcx> for Validator {
+impl<'tcx> crate::MirPass<'tcx> for Validator {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
// terribly important that they pass the validator. However, I think other passes might
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index bb05eb4c25697..6c9a6011144cd 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -304,6 +304,11 @@ where
let mut candidates = vec![];
+ if self.solver_mode() == SolverMode::Coherence {
+ if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
+ return vec![candidate];
+ }
+ }
self.assemble_impl_candidates(goal, &mut candidates);
self.assemble_builtin_impl_candidates(goal, &mut candidates);
@@ -314,11 +319,8 @@ where
self.assemble_param_env_candidates(goal, &mut candidates);
- match self.solver_mode() {
- SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
- SolverMode::Coherence => {
- self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
- }
+ if self.solver_mode() == SolverMode::Normal {
+ self.discard_impls_shadowed_by_env(goal, &mut candidates);
}
candidates
@@ -682,38 +684,34 @@ where
/// also consider impls which may get added in a downstream or sibling crate
/// or which an upstream impl may add in a minor release.
///
- /// To do so we add an ambiguous candidate in case such an unknown impl could
- /// apply to the current goal.
+ /// To do so we return a single ambiguous candidate in case such an unknown
+ /// impl could apply to the current goal.
#[instrument(level = "trace", skip_all)]
- fn assemble_coherence_unknowable_candidates>(
+ fn consider_coherence_unknowable_candidate>(
&mut self,
goal: Goal,
- candidates: &mut Vec>,
- ) {
- let cx = self.cx();
-
- candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
- |ecx| {
- let trait_ref = goal.predicate.trait_ref(cx);
- if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
- Err(NoSolution)
- } else {
- // While the trait bound itself may be unknowable, we may be able to
- // prove that a super trait is not implemented. For this, we recursively
- // prove the super trait bounds of the current goal.
- //
- // We skip the goal itself as that one would cycle.
- let predicate: I::Predicate = trait_ref.upcast(cx);
- ecx.add_goals(
- GoalSource::Misc,
- elaborate::elaborate(cx, [predicate])
- .skip(1)
- .map(|predicate| goal.with(cx, predicate)),
- );
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
- }
- },
- ))
+ ) -> Result, NoSolution> {
+ self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
+ let cx = ecx.cx();
+ let trait_ref = goal.predicate.trait_ref(cx);
+ if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
+ Err(NoSolution)
+ } else {
+ // While the trait bound itself may be unknowable, we may be able to
+ // prove that a super trait is not implemented. For this, we recursively
+ // prove the super trait bounds of the current goal.
+ //
+ // We skip the goal itself as that one would cycle.
+ let predicate: I::Predicate = trait_ref.upcast(cx);
+ ecx.add_goals(
+ GoalSource::Misc,
+ elaborate::elaborate(cx, [predicate])
+ .skip(1)
+ .map(|predicate| goal.with(cx, predicate)),
+ );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+ }
+ })
}
/// If there's a where-bound for the current goal, do not use any impl candidates
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 25115c5cafd89..c11562ae39e3c 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -19,17 +19,25 @@ use crate::errors::{
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};
+/// The context in which a block is encountered.
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
Fn,
Loop(hir::LoopSource),
Closure(Span),
- Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
+ Coroutine {
+ coroutine_span: Span,
+ kind: hir::CoroutineDesugaring,
+ source: hir::CoroutineSource,
+ },
UnlabeledBlock(Span),
UnlabeledIfBlock(Span),
LabeledBlock,
- Constant,
+ /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`.
+ AnonConst,
+ /// E.g. `const { ... }`.
+ ConstBlock,
}
#[derive(Clone)]
@@ -90,11 +98,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
- self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
+ self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
}
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
- self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
+ self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c));
}
fn visit_fn(
@@ -128,7 +136,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
&& matches!(
ck_loop.cx_stack.last(),
Some(&Normal)
- | Some(&Constant)
+ | Some(&AnonConst)
| Some(&UnlabeledBlock(_))
| Some(&UnlabeledIfBlock(_))
)
@@ -175,14 +183,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprKind::Block(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(b));
}
- hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => {
+ hir::ExprKind::Block(ref b, None)
+ if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) =>
+ {
self.with_context(Normal, |v| v.visit_block(b));
}
- hir::ExprKind::Block(ref b, None)
- if matches!(
- self.cx_stack.last(),
- Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_))
- ) =>
+ hir::ExprKind::Block(
+ ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. },
+ None,
+ ) if matches!(
+ self.cx_stack.last(),
+ Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_))
+ ) =>
{
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
}
@@ -353,7 +365,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
}
- Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => {
+ Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
self.sess.dcx().emit_err(OutsideLoop {
spans: vec![span],
name: &br_cx_kind.to_string(),
@@ -365,7 +377,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
}
fn require_label_in_labeled_block(
- &mut self,
+ &self,
span: Span,
label: &Destination,
cf_type: &str,
@@ -380,7 +392,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
false
}
- fn report_outside_loop_error(&mut self) {
+ fn report_outside_loop_error(&self) {
for (s, block) in &self.block_breaks {
self.sess.dcx().emit_err(OutsideLoop {
spans: block.spans.clone(),
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d7885e05a2ffc..6c09f97bfe731 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
} else {
let variant =
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
-
- // In the cases of either a `#[non_exhaustive]` field list or a non-public
- // field, we skip uninhabited fields in order not to reveal the
- // uninhabitedness of the whole variant.
- let is_non_exhaustive =
- variant.is_field_list_non_exhaustive() && !adt.did().is_local();
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
let is_visible =
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(*ty);
- let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
+ let skip = is_uninhabited && !is_visible;
(ty, PrivateUninhabitedField(skip))
});
cx.dropless_arena.alloc_from_iter(tys)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 5c663e0bf4b5b..45e157b108006 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5023,24 +5023,32 @@ impl<'v> Visitor<'v> for AwaitsVisitor {
}
}
+/// Suggest a new type parameter name for diagnostic purposes.
+///
+/// `name` is the preferred name you'd like to suggest if it's not in use already.
pub trait NextTypeParamName {
fn next_type_param_name(&self, name: Option<&str>) -> String;
}
impl NextTypeParamName for &[hir::GenericParam<'_>] {
fn next_type_param_name(&self, name: Option<&str>) -> String {
- // This is the list of possible parameter names that we might suggest.
+ // Type names are usually single letters in uppercase. So convert the first letter of input string to uppercase.
let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
let name = name.as_deref();
+
+ // This is the list of possible parameter names that we might suggest.
let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
- let used_names = self
+
+ // Filter out used names based on `filter_fn`.
+ let used_names: Vec = self
.iter()
- .filter_map(|p| match p.name {
+ .filter_map(|param| match param.name {
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
})
- .collect::>();
+ .collect();
+ // Find a name from `possible_names` that is not in `used_names`.
possible_names
.iter()
.find(|n| !used_names.contains(&Symbol::intern(n)))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8558520897b5c..8b55f84bccc1d 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -29,6 +29,7 @@ use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{
util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
@@ -624,14 +625,13 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
// at ambiguous goals, as for others the coherence unknowable candidate
// was irrelevant.
match goal.result() {
- Ok(Certainty::Maybe(_)) => {}
Ok(Certainty::Yes) | Err(NoSolution) => return,
+ Ok(Certainty::Maybe(_)) => {}
}
- let Goal { param_env, predicate } = goal.goal();
-
// For bound predicates we simply call `infcx.enter_forall`
// and then prove the resulting predicate as a nested goal.
+ let Goal { param_env, predicate } = goal.goal();
let trait_ref = match predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
@@ -645,7 +645,11 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
_ => return,
};
- // Add ambiguity causes for reservation impls.
+ if trait_ref.references_error() {
+ return;
+ }
+
+ let mut candidates = goal.candidates();
for cand in goal.candidates() {
if let inspect::ProbeKind::TraitCandidate {
source: CandidateSource::Impl(def_id),
@@ -664,78 +668,68 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
}
}
- // Add ambiguity causes for unknowable goals.
- let mut ambiguity_cause = None;
- for cand in goal.candidates() {
- if let inspect::ProbeKind::TraitCandidate {
- source: CandidateSource::CoherenceUnknowable,
- result: Ok(_),
- } = cand.kind()
- {
- let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
- if matches!(ty.kind(), ty::Alias(..)) {
- let ocx = ObligationCtxt::new(infcx);
- ty = ocx
- .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
- .map_err(|_| ())?;
- if !ocx.select_where_possible().is_empty() {
- return Err(());
- }
- }
- Ok(ty)
- };
+ // We also look for unknowable candidates. In case a goal is unknowable, there's
+ // always exactly 1 candidate.
+ let Some(cand) = candidates.pop() else {
+ return;
+ };
- infcx.probe(|_| {
- match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
- Err(()) => {}
- Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
- Ok(Err(conflict)) => {
- if !trait_ref.references_error() {
- // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
- let trait_ref =
- deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
-
- let self_ty = trait_ref.self_ty();
- let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
- ambiguity_cause = Some(match conflict {
- Conflict::Upstream => {
- IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_ref,
- self_ty,
- }
- }
- Conflict::Downstream => {
- IntercrateAmbiguityCause::DownstreamCrate {
- trait_ref,
- self_ty,
- }
- }
- });
- }
- }
- }
- })
- } else {
- match cand.result() {
- // We only add an ambiguity cause if the goal would otherwise
- // result in an error.
- //
- // FIXME: While this matches the behavior of the
- // old solver, it is not the only way in which the unknowable
- // candidates *weaken* coherence, they can also force otherwise
- // successful normalization to be ambiguous.
- Ok(Certainty::Maybe(_) | Certainty::Yes) => {
- ambiguity_cause = None;
- break;
- }
- Err(NoSolution) => continue,
+ let inspect::ProbeKind::TraitCandidate {
+ source: CandidateSource::CoherenceUnknowable,
+ result: Ok(_),
+ } = cand.kind()
+ else {
+ return;
+ };
+
+ let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
+ if matches!(ty.kind(), ty::Alias(..)) {
+ let ocx = ObligationCtxt::new(infcx);
+ ty = ocx
+ .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+ .map_err(|_| ())?;
+ if !ocx.select_where_possible().is_empty() {
+ return Err(());
}
}
- }
+ Ok(ty)
+ };
- if let Some(ambiguity_cause) = ambiguity_cause {
- self.causes.insert(ambiguity_cause);
- }
+ infcx.probe(|_| {
+ let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
+ Err(()) => return,
+ Ok(Ok(())) => {
+ warn!("expected an unknowable trait ref: {trait_ref:?}");
+ return;
+ }
+ Ok(Err(conflict)) => conflict,
+ };
+
+ // It is only relevant that a goal is unknowable if it would have otherwise
+ // failed.
+ let non_intercrate_infcx = infcx.fork_with_intercrate(false);
+ if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ predicate,
+ )) {
+ return;
+ }
+
+ // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+ let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+ let self_ty = trait_ref.self_ty();
+ let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
+ self.causes.insert(match conflict {
+ Conflict::Upstream => {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
+ }
+ Conflict::Downstream => {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
+ }
+ });
+ });
}
}
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index 96c939a898bd9..96998d2ec9f2c 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -58,7 +58,7 @@ pub enum Reveal {
All,
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolverMode {
/// Ordinary trait solving, using everywhere except for coherence.
Normal,
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index 12b7817c38277..0e06a820a22c3 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -195,3 +195,120 @@ conditionally compile code instead. This is notably different to the way native
platforms such as x86\_64 work, and this is due to the fact that WebAssembly
binaries must only contain code the engine understands. Native binaries work so
long as the CPU doesn't execute unknown code dynamically at runtime.
+
+## Broken `extern "C"` ABI
+
+This target has what is considered a broken `extern "C"` ABI implementation at
+this time. Notably the same signature in Rust and C will compile to different
+WebAssembly functions and be incompatible. This is considered a bug and it will
+be fixed in a future version of Rust.
+
+For example this Rust code:
+
+```rust,ignore (does-not-link)
+#[repr(C)]
+struct MyPair {
+ a: u32,
+ b: u32,
+}
+
+extern "C" {
+ fn take_my_pair(pair: MyPair) -> u32;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn call_c() -> u32 {
+ take_my_pair(MyPair { a: 1, b: 2 })
+}
+```
+
+compiles to a WebAssembly module that looks like:
+
+```wasm
+(module
+ (import "env" "take_my_pair" (func $take_my_pair (param i32 i32) (result i32)))
+ (func $call_c
+ i32.const 1
+ i32.const 2
+ call $take_my_pair
+ )
+)
+```
+
+The function when defined in C, however, looks like
+
+```c
+struct my_pair {
+ unsigned a;
+ unsigned b;
+};
+
+unsigned take_my_pair(struct my_pair pair) {
+ return pair.a + pair.b;
+}
+```
+
+```wasm
+(module
+ (import "env" "__linear_memory" (memory 0))
+ (func $take_my_pair (param i32) (result i32)
+ local.get 0
+ i32.load offset=4
+ local.get 0
+ i32.load
+ i32.add
+ )
+)
+```
+
+Notice how Rust thinks `take_my_pair` takes two `i32` parameters but C thinks it
+only takes one.
+
+The correct definition of the `extern "C"` ABI for WebAssembly is located in the
+[WebAssembly/tool-conventions](https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md)
+repository. The `wasm32-unknown-unknown` target (and only this target, not other
+WebAssembly targets Rust support) does not correctly follow this document.
+
+Example issues in the Rust repository about this bug are:
+
+* [#115666](https://github.com/rust-lang/rust/issues/115666)
+* [#129486](https://github.com/rust-lang/rust/issues/129486)
+
+This current state of the `wasm32-unknown-unknown` backend is due to an
+unfortunate accident which got relied on. The `wasm-bindgen` project prior to
+0.2.89 was incompatible with the "correct" definition of `extern "C"` and it was
+seen as not worth the tradeoff of breaking `wasm-bindgen` historically to fix
+this issue in the compiler.
+
+Thanks to the heroic efforts of many involved in this, however, `wasm-bindgen`
+0.2.89 and later are compatible with the correct definition of `extern "C"` and
+the nightly compiler currently supports a `-Zwasm-c-abi` implemented in
+[#117919](https://github.com/rust-lang/rust/pull/117919). This nightly-only flag
+can be used to indicate whether the spec-defined version of `extern "C"` should
+be used instead of the "legacy" version of
+whatever-the-Rust-target-originally-implemented. For example using the above
+code you can see (lightly edited for clarity):
+
+```shell
+$ rustc +nightly -Zwasm-c-abi=spec foo.rs --target wasm32-unknown-unknown --crate-type lib --emit obj -O
+$ wasm-tools print foo.o
+(module
+ (import "env" "take_my_pair" (func $take_my_pair (param i32) (result i32)))
+ (func $call_c (result i32)
+ ;; ...
+ )
+ ;; ...
+)
+```
+
+which shows that the C and Rust definitions of the same function now agree like
+they should.
+
+The `-Zwasm-c-abi` compiler flag is tracked in
+[#122532](https://github.com/rust-lang/rust/issues/122532) and a lint was
+implemented in [#117918](https://github.com/rust-lang/rust/issues/117918) to
+help warn users about the transition if they're using `wasm-bindgen` 0.2.88 or
+prior. The current plan is to, in the future, switch `-Zwasm-c-api=spec` to
+being the default. Some time after that the `-Zwasm-c-abi` flag and the
+"legacy" implementation will all be removed. During this process users on a
+sufficiently updated version of `wasm-bindgen` should not experience breakage.
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.panic-unwind.mir
similarity index 81%
rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.panic-unwind.mir
index 1f5bb551b8e01..d273512b91fdb 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.panic-unwind.mir
@@ -1,11 +1,11 @@
-// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
+// MIR for `main::{closure#0}::{closure#0}::{closure#0}` after built
-fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:55:53: 58:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
debug a => (_1.0: i32);
- debug b => (_1.1: i32);
+ debug b => (*(_1.1: &i32));
let mut _0: ();
let _3: i32;
scope 1 {
@@ -28,7 +28,7 @@ yields ()
_4 = &_3;
FakeRead(ForLet(None), _4);
StorageLive(_5);
- _5 = &(_1.1: i32);
+ _5 = &(*(_1.1: &i32));
FakeRead(ForLet(None), _5);
_0 = const ();
StorageDead(_5);
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.panic-unwind.mir
similarity index 80%
rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.panic-unwind.mir
index 1f5bb551b8e01..43f33219c7b42 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.panic-unwind.mir
@@ -1,6 +1,6 @@
-// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
+// MIR for `main::{closure#0}::{closure#0}::{closure#1}` after built
-fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:55:53: 58:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
index a984845fd2c11..ce1d06ce1d3e9 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -1,10 +1,10 @@
// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
-fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:53:33: 53:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10} {
- let mut _0: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10};
+fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:55:33: 55:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:55:53: 58:10} {
+ let mut _0: {async closure body@$DIR/async_closure_shims.rs:55:53: 58:10};
bb0: {
- _0 = {coroutine@$DIR/async_closure_shims.rs:53:53: 56:10 (#0)} { a: move _2, b: move (_1.0: i32) };
+ _0 = {coroutine@$DIR/async_closure_shims.rs:55:53: 58:10 (#0)} { a: move _2, b: move (_1.0: i32) };
return;
}
}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.panic-unwind.mir
similarity index 86%
rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir
rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.panic-unwind.mir
index 17fa93148064f..b4765c0b74ca8 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.panic-unwind.mir
@@ -1,6 +1,6 @@
-// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move
+// MIR for `main::{closure#0}::{closure#1}::{closure#0}` after built
-fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.panic-unwind.mir
similarity index 80%
rename from tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
rename to tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.panic-unwind.mir
index 17fa93148064f..bf5be94b1aebf 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.panic-unwind.mir
@@ -1,6 +1,6 @@
-// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move
+// MIR for `main::{closure#0}::{closure#1}::{closure#1}` after built
-fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#1}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir
index aab9f7b03b9ab..8452c79bf41bb 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -1,10 +1,10 @@
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_move
-fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
- let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
+fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:64:33: 64:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10} {
+ let mut _0: {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10};
bb0: {
- _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: move (_1.0: &i32) };
+ _0 = {coroutine@$DIR/async_closure_shims.rs:64:48: 67:10 (#0)} { a: move _2, b: move (_1.0: &i32) };
return;
}
}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
index 3fdc81791deef..08abe7197224c 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
@@ -1,10 +1,10 @@
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
-fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
- let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
+fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:64:33: 64:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10} {
+ let mut _0: {async closure body@$DIR/async_closure_shims.rs:64:48: 67:10};
bb0: {
- _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: copy ((*_1).0: &i32) };
+ _0 = {coroutine@$DIR/async_closure_shims.rs:64:48: 67:10 (#0)} { a: move _2, b: copy ((*_1).0: &i32) };
return;
}
}
diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs
index 57c55ef055cd7..4d44025ac762a 100644
--- a/tests/mir-opt/async_closure_shims.rs
+++ b/tests/mir-opt/async_closure_shims.rs
@@ -22,7 +22,7 @@ pub fn block_on(fut: impl Future