os: windows-latest-xl
- name: i686-mingw-1
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
SCRIPT: make ci-mingw-subset-1
NO_DOWNLOAD_CI_LLVM: 1
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: i686-mingw-2
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
SCRIPT: make ci-mingw-subset-2
NO_DOWNLOAD_CI_LLVM: 1
CUSTOM_MINGW: 1
- name: x86_64-mingw-1
env:
SCRIPT: make ci-mingw-subset-1
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
NO_DOWNLOAD_CI_LLVM: 1
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: x86_64-mingw-2
env:
SCRIPT: make ci-mingw-subset-2
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
NO_DOWNLOAD_CI_LLVM: 1
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: dist-x86_64-msvc
env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin"
- SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
+ SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
DIST_REQUIRE_ALL_TOOLS: 1
os: windows-latest-xl
- name: dist-i686-msvc
os: windows-latest-xl
- name: dist-i686-mingw
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
NO_DOWNLOAD_CI_LLVM: 1
SCRIPT: python x.py dist bootstrap --include-default-paths
CUSTOM_MINGW: 1
- name: dist-x86_64-mingw
env:
SCRIPT: python x.py dist bootstrap --include-default-paths
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
NO_DOWNLOAD_CI_LLVM: 1
CUSTOM_MINGW: 1
DIST_REQUIRE_ALL_TOOLS: 1
| mir::StatementKind::AscribeUserType(..)
| mir::StatementKind::Coverage(..)
| mir::StatementKind::Intrinsic(..)
+ | mir::StatementKind::ConstEvalCounter
| mir::StatementKind::Nop => {}
}
}
"{place_name} {partially_str}moved due to this method call{loop_message}",
),
);
+
let infcx = tcx.infer_ctxt().build();
+ // Erase and shadow everything that could be passed to the new infcx.
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+ let method_substs = tcx.erase_regions(method_substs);
+
if let ty::Adt(def, substs) = ty.kind()
&& Some(def.did()) == tcx.lang_items().pin_type()
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
LocalMutationIsAllowed::Yes,
);
}
- StatementKind::Nop
+ StatementKind::ConstEvalCounter
+ | StatementKind::Nop
| StatementKind::Retag { .. }
| StatementKind::Deinit(..)
| StatementKind::SetDiscriminant { .. } => {
StatementKind::AscribeUserType(..)
// Doesn't have any language semantics
| StatementKind::Coverage(..)
- // Does not actually affect borrowck
+ // These do not actually affect borrowck
+ | StatementKind::ConstEvalCounter
| StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
| StatementKind::StorageDead(..)
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::{path_std, pathvec_std};
-use rustc_ast::MetaItem;
+use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
+ // Order in which to perform matching
+ let tag_then_data = if let Annotatable::Item(item) = item
+ && let ItemKind::Enum(def, _) = &item.kind {
+ let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
+ match dataful.iter().filter(|&&b| b).count() {
+ // No data, placing the tag check first makes codegen simpler
+ 0 => true,
+ 1..=2 => false,
+ _ => {
+ (0..dataful.len()-1).any(|i| {
+ if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) {
+ idx >= 2
+ } else {
+ false
+ }
+ })
+ }
+ }
+ } else {
+ true
+ };
let partial_cmp_def = MethodDef {
name: sym::partial_cmp,
generics: Bounds::empty(),
attributes: attrs,
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
- cs_partial_cmp(cx, span, substr)
+ cs_partial_cmp(cx, span, substr, tag_then_data)
})),
};
trait_def.expand(cx, mitem, item, push)
}
-pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+fn cs_partial_cmp(
+ cx: &mut ExtCtxt<'_>,
+ span: Span,
+ substr: &Substructure<'_>,
+ tag_then_data: bool,
+) -> BlockOrExpr {
let test_id = Ident::new(sym::cmp, span);
let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
let args = vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
}
- CsFold::Combine(span, expr1, expr2) => {
- let eq_arm =
- cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
- let neq_arm =
- cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
- cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+ CsFold::Combine(span, mut expr1, expr2) => {
+ // When the item is an enum, this expands to
+ // ```
+ // match (expr2) {
+ // Some(Ordering::Equal) => expr1,
+ // cmp => cmp
+ // }
+ // ```
+ // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
+ // against the enum variants. This means that we begin by comparing the enum tags,
+ // before either inspecting their contents (if they match), or returning
+ // the `cmp::Ordering` of comparing the enum tags.
+ // ```
+ // match partial_cmp(self_tag, other_tag) {
+ // Some(Ordering::Equal) => match (self, other) {
+ // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+ // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
+ // _ => Some(Ordering::Equal)
+ // }
+ // cmp => cmp
+ // }
+ // ```
+ // If we have any certain enum layouts, flipping this results in better codegen
+ // ```
+ // match (self, other) {
+ // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
+ // _ => partial_cmp(self_tag, other_tag)
+ // }
+ // ```
+ // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
+
+ if !tag_then_data
+ && let ExprKind::Match(_, arms) = &mut expr1.kind
+ && let Some(last) = arms.last_mut()
+ && let PatKind::Wild = last.pat.kind {
+ last.body = expr2;
+ expr1
+ } else {
+ let eq_arm =
+ cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
+ let neq_arm =
+ cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
+ cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+ }
}
CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
},
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Deinit(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop
| StatementKind::FakeRead(..)
| StatementKind::Retag { .. }
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _)
| StatementKind::Coverage(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
}
//
// FIXME(#34960)
let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or("");
- let custom_llvm_used = cfg_llvm_root.trim() != "";
+ let custom_llvm_used = !cfg_llvm_root.trim().is_empty();
if !custom_llvm_used && target_data_layout != llvm_data_layout {
bug!(
// Arguments get assigned to by means of the function being called
for arg in mir.args_iter() {
- analyzer.assign(arg, mir::START_BLOCK.start_location());
+ analyzer.assign(arg, DefLocation::Argument);
}
// If there exists a local definition that dominates all uses of that local,
/// A scalar or a scalar pair local that is neither defined nor used.
Unused,
/// A scalar or a scalar pair local with a single definition that dominates all uses.
- SSA(mir::Location),
+ SSA(DefLocation),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum DefLocation {
+ Argument,
+ Body(Location),
+}
+
+impl DefLocation {
+ fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool {
+ match self {
+ DefLocation::Argument => true,
+ DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
+ }
+ }
}
struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
}
impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
- fn assign(&mut self, local: mir::Local, location: Location) {
+ fn assign(&mut self, local: mir::Local, location: DefLocation) {
let kind = &mut self.locals[local];
match *kind {
LocalKind::ZST => {}
LocalKind::Memory => {}
- LocalKind::Unused => {
- *kind = LocalKind::SSA(location);
- }
- LocalKind::SSA(_) => {
- *kind = LocalKind::Memory;
- }
+ LocalKind::Unused => *kind = LocalKind::SSA(location),
+ LocalKind::SSA(_) => *kind = LocalKind::Memory,
}
}
debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
if let Some(local) = place.as_local() {
- self.assign(local, location);
+ self.assign(local, DefLocation::Body(location));
if self.locals[local] != LocalKind::Memory {
let decl_span = self.fx.mir.local_decls[local].source_info.span;
if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
match context {
PlaceContext::MutatingUse(MutatingUseContext::Call)
| PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
- self.assign(local, location);
+ self.assign(local, DefLocation::Body(location));
}
PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
mir::StatementKind::FakeRead(..)
| mir::StatementKind::Retag { .. }
| mir::StatementKind::AscribeUserType(..)
+ | mir::StatementKind::ConstEvalCounter
| mir::StatementKind::Nop => {}
}
}
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
}
- fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
- // The step limit has already been hit in a previous call to `before_terminator`.
+ fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+ // The step limit has already been hit in a previous call to `increment_const_eval_counter`.
if ecx.machine.steps_remaining == 0 {
return Ok(());
}
}
/// Called before a basic block terminator is executed.
- /// You can use this to detect endlessly running programs.
#[inline]
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
Ok(())
}
+ /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
+ /// You can use this to detect long or endlessly running programs.
+ #[inline]
+ fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+ Ok(())
+ }
+
/// Called before a global allocation is accessed.
/// `def_id` is `Some` if this is the "lazy" allocation of a static.
#[inline]
// FIXME(#73156): Handle source code coverage in const eval
Coverage(..) => {}
+ ConstEvalCounter => {
+ M::increment_const_eval_counter(self)?;
+ }
+
// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.
Nop => {}
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
}
StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Coverage(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
// This loop computes the semi[w] for w.
semi[w] = w;
for v in graph.predecessors(pre_order_to_real[w]) {
- // Reachable vertices may have unreachable predecessors, so ignore any of them
+ // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them.
+ //
+ // Ignore blocks which are not connected to the entry block.
+ //
+ // The algorithm that was used to traverse the graph and build the
+ // `pre_order_to_real` and `real_to_pre_order` vectors does so by
+ // starting from the entry block and following the successors.
+ // Therefore, any blocks not reachable from the entry block will be
+ // set to `None` in the `pre_order_to_real` vector.
+ //
+ // For example, in this graph, A and B should be skipped:
+ //
+ // ┌─────┐
+ // │ │
+ // └──┬──┘
+ // │
+ // ┌──▼──┐ ┌─────┐
+ // │ │ │ A │
+ // └──┬──┘ └──┬──┘
+ // │ │
+ // ┌───────┴───────┐ │
+ // │ │ │
+ // ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
+ // │ │ │ │ │ B │
+ // └──┬──┘ └──┬──┘ └──┬──┘
+ // │ └──────┬─────┘
+ // ┌──▼──┐ │
+ // │ │ │
+ // └──┬──┘ ┌──▼──┐
+ // │ │ │
+ // │ └─────┘
+ // ┌──▼──┐
+ // │ │
+ // └──┬──┘
+ // │
+ // ┌──▼──┐
+ // │ │
+ // └─────┘
+ //
+ // ...this may be the case if a MirPass modifies the CFG to remove
+ // or rearrange certain blocks/edges.
let Some(v) = real_to_pre_order[v] else {
continue
};
}
}
+/// Tracks the list of dominators for each node.
#[derive(Clone, Debug)]
pub struct Dominators<N: Idx> {
post_order_rank: IndexVec<N, usize>,
+ // Even though we track only the immediate dominator of each node, it's
+ // possible to get its full list of dominators by looking up the dominator
+ // of each dominator. (See the `impl Iterator for Iter` definition).
immediate_dominators: IndexVec<N, Option<N>>,
}
impl<Node: Idx> Dominators<Node> {
+ /// Whether the given Node has an immediate dominator.
pub fn is_reachable(&self, node: Node) -> bool {
self.immediate_dominators[node].is_some()
}
self.immediate_dominators[node].unwrap()
}
+ /// Provides an iterator over each dominator up the CFG, for the given Node.
+ /// See the `impl Iterator for Iter` definition to understand how this works.
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
assert!(self.is_reachable(node), "node {node:?} is not reachable");
Iter { dominators: self, node: Some(node) }
out
}
+ ThirFlat => {
+ let mut out = String::new();
+ abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
+ debug!("pretty printing THIR flat");
+ for did in tcx.hir().body_owners() {
+ let _ = writeln!(
+ out,
+ "{:?}:\n{}\n",
+ did,
+ tcx.thir_flat(ty::WithOptConstParam::unknown(did))
+ );
+ }
+ out
+ }
+
_ => unreachable!(),
};
.note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
.help = for more information, see https://doc.rust-lang.org/reference/destructors.html
+lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
lint_identifier_non_ascii_char = identifier contains non-ASCII characters
lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
} with a body
.suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
+parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
+ .suggestion_remove_eq = use `..=` instead
+ .note = inclusive ranges end with a single equals sign (`..=`)
+
+parse_inclusive_range_match_arrow = unexpected `=>` after open range
+ .suggestion_add_space = add a space between the pattern and `=>`
+
+parse_inclusive_range_no_end = inclusive range with no end
+ .suggestion_open_range = use `..` instead
+ .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
parse_struct_literal_not_allowed_here = struct literals are not allowed here
.suggestion = surround the struct literal with parentheses
(active, intrinsics, "1.0.0", None, None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
(active, lang_items, "1.0.0", None, None),
+ /// Allows the `multiple_supertrait_upcastable` lint.
+ (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
/// Allows using `#[omit_gdb_pretty_printer_section]`.
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
/// Allows using `#[prelude_import]` on glob `use` items.
_ => {}
}
if !trait_should_be_self.is_empty() {
- if tcx.object_safety_violations(trait_def_id).is_empty() {
+ if tcx.check_is_object_safe(trait_def_id) {
return;
}
let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
});
for component_def_id in component_def_ids {
- if !tcx.is_object_safe(component_def_id) {
+ if !tcx.check_is_object_safe(component_def_id) {
// Without the 'object_safe_for_dispatch' feature this is an error
// which will be reported by wfcheck. Ignore it here.
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
.trait_ref()
.and_then(|t| t.trait_def_id())
.map_or(false, |def_id| {
- fcx.tcx.object_safety_violations(def_id).is_empty()
+ fcx.tcx.check_is_object_safe(def_id)
})
})
}
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, List};
+use rustc_middle::ty::{self, List};
use rustc_span::source_map::Span;
pub use rustc_middle::infer::canonical::*;
variables: &List<CanonicalVarInfo<'tcx>>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> CanonicalVarValues<'tcx> {
- let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables
- .iter()
- .map(|info| self.instantiate_canonical_var(span, info, &universe_map))
- .collect();
-
- CanonicalVarValues { var_values }
+ CanonicalVarValues {
+ var_values: self.tcx.mk_substs(
+ variables
+ .iter()
+ .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
+ ),
+ }
}
/// Given the "info" about a canonical variable, creates a fresh
// given variable in the loop above, use that. Otherwise, use
// a fresh inference variable.
let result_subst = CanonicalVarValues {
- var_values: query_response
- .variables
- .iter()
- .enumerate()
- .map(|(index, info)| {
+ var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map(
+ |(index, info)| {
if info.is_existential() {
match opt_values[BoundVar::new(index)] {
Some(k) => k,
universe_map[u.as_usize()]
})
}
- })
- .collect(),
+ },
+ )),
};
let mut obligations = vec![];
value
} else {
let delegate = FnMutDelegate {
- regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() {
+ regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() {
GenericArgKind::Lifetime(l) => l,
r => bug!("{:?} is a region but value is {:?}", br, r),
},
- types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() {
+ types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() {
GenericArgKind::Type(ty) => ty,
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
},
- consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack()
- {
+ consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() {
GenericArgKind::Const(ct) => ct,
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
},
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
+ tracked!(tiny_const_eval_limit, true);
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(trait_solver, TraitSolver::Chalk);
tracked!(translate_remapped_path_to_local_path, false);
mod levels;
mod lints;
mod methods;
+mod multiple_supertrait_upcastable;
mod non_ascii_idents;
mod non_fmt_panic;
mod nonstandard_style;
use internal::*;
use let_underscore::*;
use methods::*;
+use multiple_supertrait_upcastable::*;
use non_ascii_idents::*;
use non_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
InvalidAtomicOrdering: InvalidAtomicOrdering,
NamedAsmLabels: NamedAsmLabels,
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
+ MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
]
]
);
pub unwrap: Span,
}
+// multiple_supertrait_upcastable.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_multple_supertrait_upcastable)]
+pub struct MultipleSupertraitUpcastable {
+ pub ident: Ident,
+}
+
// non_ascii_idents.rs
#[derive(LintDiagnostic)]
#[diag(lint_identifier_non_ascii_char)]
--- /dev/null
+use crate::{LateContext, LateLintPass, LintContext};
+
+use rustc_hir as hir;
+use rustc_span::sym;
+
+declare_lint! {
+ /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
+ /// supertraits.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// trait A {}
+ /// trait B {}
+ ///
+ /// #[warn(multiple_supertrait_upcastable)]
+ /// trait C: A + B {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// To support upcasting with multiple supertraits, we need to store multiple vtables and this
+ /// can result in extra space overhead, even if no code actually uses upcasting.
+ /// This lint allows users to identify when such scenarios occur and to decide whether the
+ /// additional overhead is justified.
+ pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
+ Allow,
+ "detect when an object-safe trait has multiple supertraits",
+ @feature_gate = sym::multiple_supertrait_upcastable;
+}
+
+declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+ let def_id = item.owner_id.to_def_id();
+ // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because
+ // the latter will report `where_clause_object_safety` lint.
+ if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
+ && cx.tcx.object_safety_violations(def_id).is_empty()
+ {
+ let direct_super_traits_iter = cx.tcx
+ .super_predicates_of(def_id)
+ .predicates
+ .into_iter()
+ .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
+ if direct_super_traits_iter.count() > 1 {
+ cx.emit_spanned_lint(
+ MULTIPLE_SUPERTRAIT_UPCASTABLE,
+ cx.tcx.def_span(def_id),
+ crate::lints::MultipleSupertraitUpcastable {
+ ident: item.ident
+ },
+ );
+ }
+ }
+ }
+}
///
/// ### Explanation
///
- /// Previously, there were very like checks being performed on `#[doc(..)]`
- /// unlike the other attributes. It'll now catch all the issues that it
- /// silently ignored previously.
+ /// Previously, incorrect usage of the `#[doc(..)]` attribute was not
+ /// being validated. Usually these should be rejected as a hard error,
+ /// but this lint was introduced to avoid breaking any existing
+ /// crates which included them.
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard
+ /// error in the future. See [issue #82730] for more details.
+ ///
+ /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730
pub INVALID_DOC_ATTRIBUTES,
Warn,
"detects invalid `#[doc(...)]` attributes",
if encode_opt {
record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
- if let DefKind::Generator = self.tcx.def_kind(def_id) {
+ if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir {
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
}
}
use crate::mir::ConstraintCategory;
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
-use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use smallvec::SmallVec;
-use std::iter;
use std::ops::Index;
/// A "canonicalized" type `V` is one where all free inference
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct CanonicalVarValues<'tcx> {
- pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
+ pub var_values: ty::SubstsRef<'tcx>,
}
impl CanonicalVarValues<'_> {
pub fn is_identity(&self) -> bool {
- self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() {
+ self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
ty::GenericArgKind::Lifetime(r) => {
- matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv)
+ matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
}
ty::GenericArgKind::Type(ty) => {
- matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv)
+ matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
}
ty::GenericArgKind::Const(ct) => {
- matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv)
+ matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
}
})
}
}
impl<'tcx> CanonicalVarValues<'tcx> {
+ // Given a list of canonical variables, construct a set of values which are
+ // the identity response.
+ pub fn make_identity(
+ tcx: TyCtxt<'tcx>,
+ infos: CanonicalVarInfos<'tcx>,
+ ) -> CanonicalVarValues<'tcx> {
+ CanonicalVarValues {
+ var_values: tcx.mk_substs(infos.iter().enumerate().map(
+ |(i, info)| -> ty::GenericArg<'tcx> {
+ match info.kind {
+ CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => tcx
+ .mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()))
+ .into(),
+ CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(i),
+ kind: ty::BrAnon(i as u32, None),
+ };
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+ }
+ CanonicalVarKind::Const(_, ty)
+ | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
+ .mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)),
+ ty,
+ )
+ .into(),
+ }
+ },
+ )),
+ }
+ }
+
/// Creates dummy var values which should not be used in a
/// canonical response.
pub fn dummy() -> CanonicalVarValues<'tcx> {
- CanonicalVarValues { var_values: Default::default() }
+ CanonicalVarValues { var_values: ty::List::empty() }
}
#[inline]
pub fn len(&self) -> usize {
self.var_values.len()
}
-
- /// Makes an identity substitution from this one: each bound var
- /// is matched to the same bound var, preserving the original kinds.
- /// For example, if we have:
- /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
- /// we'll return a substitution `subst` with:
- /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
- pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
- use crate::ty::subst::GenericArgKind;
-
- CanonicalVarValues {
- var_values: iter::zip(&self.var_values, 0..)
- .map(|(kind, i)| match kind.unpack() {
- GenericArgKind::Type(..) => {
- tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
- }
- GenericArgKind::Lifetime(..) => {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(i),
- kind: ty::BrAnon(i, None),
- };
- tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
- }
- GenericArgKind::Const(ct) => tcx
- .mk_const(
- ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
- ct.ty(),
- )
- .into(),
- })
- .collect(),
- }
- }
}
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
type Item = GenericArg<'tcx>;
- type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
+ type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;
fn into_iter(self) -> Self::IntoIter {
- self.var_values.iter().cloned()
+ self.var_values.iter()
}
}
type Output = GenericArg<'tcx>;
fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
- &self.var_values[value]
+ &self.var_values[value.as_usize()]
}
}
}
Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
+ ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
Nop => write!(fmt, "nop"),
}
}
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",
Intrinsic(..) => "Intrinsic",
+ ConstEvalCounter => "ConstEvalCounter",
Nop => "Nop",
}
}
/// This avoids adding a new block and a terminator for simple intrinsics.
Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
+ /// Instructs the const eval interpreter to increment a counter; this counter is used to track
+ /// how many steps the interpreter has taken. It is used to prevent the user from writing const
+ /// code that runs for too long or infinitely. Other than in the const eval interpreter, this
+ /// is a no-op.
+ ConstEvalCounter,
+
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
}
}
}
}
+ StatementKind::ConstEvalCounter => {}
StatementKind::Nop => {}
}
}
desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
}
+ /// Create a list-like THIR representation for debugging.
+ query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+ no_hash
+ arena_cache
+ desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
/// Set of all the `DefId`s in this crate that have MIR associated with
/// them. This includes all the body owners, but also things like struct
/// constructors.
query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
+ query check_is_object_safe(trait_id: DefId) -> bool {
+ desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) }
+ }
/// Gets the ParameterEnvironment for a given item; this environment
/// will be in "user-facing" mode, meaning that it is suitable for
use std::fmt;
use std::ops::Index;
+pub mod print;
pub mod visit;
macro_rules! thir_with_elements {
--- /dev/null
+use crate::thir::*;
+use crate::ty::{self, TyCtxt};
+
+use std::fmt::{self, Write};
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String {
+ let mut printer = ThirPrinter::new(thir);
+ printer.print();
+ printer.into_buffer()
+ }
+}
+
+struct ThirPrinter<'a, 'tcx> {
+ thir: &'a Thir<'tcx>,
+ fmt: String,
+}
+
+const INDENT: &str = " ";
+
+macro_rules! print_indented {
+ ($writer:ident, $s:expr, $indent_lvl:expr) => {
+ let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat();
+ writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter");
+ };
+}
+
+impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.fmt.push_str(s);
+ Ok(())
+ }
+}
+
+impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
+ fn new(thir: &'a Thir<'tcx>) -> Self {
+ Self { thir, fmt: String::new() }
+ }
+
+ fn print(&mut self) {
+ print_indented!(self, "params: [", 0);
+ for param in self.thir.params.iter() {
+ self.print_param(param, 1);
+ }
+ print_indented!(self, "]", 0);
+
+ print_indented!(self, "body:", 0);
+ let expr = ExprId::from_usize(self.thir.exprs.len() - 1);
+ self.print_expr(expr, 1);
+ }
+
+ fn into_buffer(self) -> String {
+ self.fmt
+ }
+
+ fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) {
+ let Param { pat, ty, ty_span, self_kind, hir_id } = param;
+
+ print_indented!(self, "Param {", depth_lvl);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+ print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1);
+ print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1);
+ print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1);
+
+ if let Some(pat) = pat {
+ print_indented!(self, "param: Some( ", depth_lvl + 1);
+ self.print_pat(pat, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl + 1);
+ } else {
+ print_indented!(self, "param: None", depth_lvl + 1);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) {
+ let Block {
+ targeted_by_break,
+ opt_destruction_scope,
+ span,
+ region_scope,
+ stmts,
+ expr,
+ safety_mode,
+ } = &self.thir.blocks[block_id];
+
+ print_indented!(self, "Block {", depth_lvl);
+ print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1);
+ print_indented!(
+ self,
+ format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+ depth_lvl + 1
+ );
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+ print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1);
+
+ if stmts.len() > 0 {
+ print_indented!(self, "stmts: [", depth_lvl + 1);
+ for stmt in stmts.iter() {
+ self.print_stmt(*stmt, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ } else {
+ print_indented!(self, "stmts: []", depth_lvl + 1);
+ }
+
+ if let Some(expr_id) = expr {
+ print_indented!(self, "expr:", depth_lvl + 1);
+ self.print_expr(*expr_id, depth_lvl + 2);
+ } else {
+ print_indented!(self, "expr: []", depth_lvl + 1);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) {
+ let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id];
+
+ print_indented!(self, "Stmt {", depth_lvl);
+ print_indented!(
+ self,
+ format!("opt_destruction_scope: {:?}", opt_destruction_scope),
+ depth_lvl + 1
+ );
+
+ match kind {
+ StmtKind::Expr { scope, expr } => {
+ print_indented!(self, "kind: Expr {", depth_lvl + 1);
+ print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2);
+ print_indented!(self, "expr:", depth_lvl + 2);
+ self.print_expr(*expr, depth_lvl + 3);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ StmtKind::Let {
+ remainder_scope,
+ init_scope,
+ pattern,
+ initializer,
+ else_block,
+ lint_level,
+ } => {
+ print_indented!(self, "kind: Let {", depth_lvl + 1);
+ print_indented!(
+ self,
+ format!("remainder_scope: {:?}", remainder_scope),
+ depth_lvl + 2
+ );
+ print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2);
+
+ print_indented!(self, "pattern: ", depth_lvl + 2);
+ self.print_pat(pattern, depth_lvl + 3);
+ print_indented!(self, ",", depth_lvl + 2);
+
+ if let Some(init) = initializer {
+ print_indented!(self, "initializer: Some(", depth_lvl + 2);
+ self.print_expr(*init, depth_lvl + 3);
+ print_indented!(self, ")", depth_lvl + 2);
+ } else {
+ print_indented!(self, "initializer: None", depth_lvl + 2);
+ }
+
+ if let Some(else_block) = else_block {
+ print_indented!(self, "else_block: Some(", depth_lvl + 2);
+ self.print_block(*else_block, depth_lvl + 3);
+ print_indented!(self, ")", depth_lvl + 2);
+ } else {
+ print_indented!(self, "else_block: None", depth_lvl + 2);
+ }
+
+ print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) {
+ let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr];
+ print_indented!(self, "Expr {", depth_lvl);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+ print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ print_indented!(self, "kind: ", depth_lvl + 1);
+ self.print_expr_kind(kind, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) {
+ use rustc_middle::thir::ExprKind::*;
+
+ match expr_kind {
+ Scope { region_scope, value, lint_level } => {
+ print_indented!(self, "Scope {", depth_lvl);
+ print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
+ print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+ print_indented!(self, "value:", depth_lvl + 1);
+ self.print_expr(*value, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Box { value } => {
+ print_indented!(self, "Box {", depth_lvl);
+ self.print_expr(*value, depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ If { if_then_scope, cond, then, else_opt } => {
+ print_indented!(self, "If {", depth_lvl);
+ print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1);
+ print_indented!(self, "cond:", depth_lvl + 1);
+ self.print_expr(*cond, depth_lvl + 2);
+ print_indented!(self, "then:", depth_lvl + 1);
+ self.print_expr(*then, depth_lvl + 2);
+
+ if let Some(else_expr) = else_opt {
+ print_indented!(self, "else:", depth_lvl + 1);
+ self.print_expr(*else_expr, depth_lvl + 2);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+ Call { fun, args, ty, from_hir_call, fn_span } => {
+ print_indented!(self, "Call {", depth_lvl);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+ print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1);
+ print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1);
+ print_indented!(self, "fun:", depth_lvl + 1);
+ self.print_expr(*fun, depth_lvl + 2);
+
+ if args.len() > 0 {
+ print_indented!(self, "args: [", depth_lvl + 1);
+ for arg in args.iter() {
+ self.print_expr(*arg, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ } else {
+ print_indented!(self, "args: []", depth_lvl + 1);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+ Deref { arg } => {
+ print_indented!(self, "Deref {", depth_lvl);
+ self.print_expr(*arg, depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Binary { op, lhs, rhs } => {
+ print_indented!(self, "Binary {", depth_lvl);
+ print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "rhs:", depth_lvl + 1);
+ self.print_expr(*rhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ LogicalOp { op, lhs, rhs } => {
+ print_indented!(self, "LogicalOp {", depth_lvl);
+ print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "rhs:", depth_lvl + 1);
+ self.print_expr(*rhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Unary { op, arg } => {
+ print_indented!(self, "Unary {", depth_lvl);
+ print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+ print_indented!(self, "arg:", depth_lvl + 1);
+ self.print_expr(*arg, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Cast { source } => {
+ print_indented!(self, "Cast {", depth_lvl);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Use { source } => {
+ print_indented!(self, "Use {", depth_lvl);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ NeverToAny { source } => {
+ print_indented!(self, "NeverToAny {", depth_lvl);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Pointer { cast, source } => {
+ print_indented!(self, "Pointer {", depth_lvl);
+ print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Loop { body } => {
+ print_indented!(self, "Loop (", depth_lvl);
+ print_indented!(self, "body:", depth_lvl + 1);
+ self.print_expr(*body, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl);
+ }
+ Let { expr, pat } => {
+ print_indented!(self, "Let {", depth_lvl);
+ print_indented!(self, "expr:", depth_lvl + 1);
+ self.print_expr(*expr, depth_lvl + 2);
+ print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Match { scrutinee, arms } => {
+ print_indented!(self, "Match {", depth_lvl);
+ print_indented!(self, "scrutinee:", depth_lvl + 1);
+ self.print_expr(*scrutinee, depth_lvl + 2);
+
+ print_indented!(self, "arms: [", depth_lvl + 1);
+ for arm_id in arms.iter() {
+ self.print_arm(*arm_id, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Block { block } => self.print_block(*block, depth_lvl),
+ Assign { lhs, rhs } => {
+ print_indented!(self, "Assign {", depth_lvl);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "rhs:", depth_lvl + 1);
+ self.print_expr(*rhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ AssignOp { op, lhs, rhs } => {
+ print_indented!(self, "AssignOp {", depth_lvl);
+ print_indented!(self, format!("op: {:?}", op), depth_lvl + 1);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "rhs:", depth_lvl + 1);
+ self.print_expr(*rhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Field { lhs, variant_index, name } => {
+ print_indented!(self, "Field {", depth_lvl);
+ print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1);
+ print_indented!(self, format!("name: {:?}", name), depth_lvl + 1);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Index { lhs, index } => {
+ print_indented!(self, "Index {", depth_lvl);
+ print_indented!(self, format!("index: {:?}", index), depth_lvl + 1);
+ print_indented!(self, "lhs:", depth_lvl + 1);
+ self.print_expr(*lhs, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ VarRef { id } => {
+ print_indented!(self, "VarRef {", depth_lvl);
+ print_indented!(self, format!("id: {:?}", id), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ UpvarRef { closure_def_id, var_hir_id } => {
+ print_indented!(self, "UpvarRef {", depth_lvl);
+ print_indented!(
+ self,
+ format!("closure_def_id: {:?}", closure_def_id),
+ depth_lvl + 1
+ );
+ print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Borrow { borrow_kind, arg } => {
+ print_indented!(self, "Borrow (", depth_lvl);
+ print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1);
+ print_indented!(self, "arg:", depth_lvl + 1);
+ self.print_expr(*arg, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl);
+ }
+ AddressOf { mutability, arg } => {
+ print_indented!(self, "AddressOf {", depth_lvl);
+ print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1);
+ print_indented!(self, "arg:", depth_lvl + 1);
+ self.print_expr(*arg, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Break { label, value } => {
+ print_indented!(self, "Break (", depth_lvl);
+ print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+
+ if let Some(value) = value {
+ print_indented!(self, "value:", depth_lvl + 1);
+ self.print_expr(*value, depth_lvl + 2);
+ }
+
+ print_indented!(self, ")", depth_lvl);
+ }
+ Continue { label } => {
+ print_indented!(self, "Continue {", depth_lvl);
+ print_indented!(self, format!("label: {:?}", label), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Return { value } => {
+ print_indented!(self, "Return {", depth_lvl);
+ print_indented!(self, "value:", depth_lvl + 1);
+
+ if let Some(value) = value {
+ self.print_expr(*value, depth_lvl + 2);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+ ConstBlock { did, substs } => {
+ print_indented!(self, "ConstBlock {", depth_lvl);
+ print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);
+ print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Repeat { value, count } => {
+ print_indented!(self, "Repeat {", depth_lvl);
+ print_indented!(self, format!("count: {:?}", count), depth_lvl + 1);
+ print_indented!(self, "value:", depth_lvl + 1);
+ self.print_expr(*value, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Array { fields } => {
+ print_indented!(self, "Array {", depth_lvl);
+ print_indented!(self, "fields: [", depth_lvl + 1);
+ for field_id in fields.iter() {
+ self.print_expr(*field_id, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Tuple { fields } => {
+ print_indented!(self, "Tuple {", depth_lvl);
+ print_indented!(self, "fields: [", depth_lvl + 1);
+ for field_id in fields.iter() {
+ self.print_expr(*field_id, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Adt(adt_expr) => {
+ print_indented!(self, "Adt {", depth_lvl);
+ self.print_adt_expr(&**adt_expr, depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ PlaceTypeAscription { source, user_ty } => {
+ print_indented!(self, "PlaceTypeAscription {", depth_lvl);
+ print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ ValueTypeAscription { source, user_ty } => {
+ print_indented!(self, "ValueTypeAscription {", depth_lvl);
+ print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+ print_indented!(self, "source:", depth_lvl + 1);
+ self.print_expr(*source, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Closure(closure_expr) => {
+ print_indented!(self, "Closure {", depth_lvl);
+ print_indented!(self, "closure_expr:", depth_lvl + 1);
+ self.print_closure_expr(&**closure_expr, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Literal { lit, neg } => {
+ print_indented!(
+ self,
+ format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg),
+ depth_lvl
+ );
+ }
+ NonHirLiteral { lit, user_ty } => {
+ print_indented!(self, "NonHirLiteral {", depth_lvl);
+ print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1);
+ print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ ZstLiteral { user_ty } => {
+ print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl);
+ }
+ NamedConst { def_id, substs, user_ty } => {
+ print_indented!(self, "NamedConst {", depth_lvl);
+ print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+ print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1);
+ print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ ConstParam { param, def_id } => {
+ print_indented!(self, "ConstParam {", depth_lvl);
+ print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+ print_indented!(self, format!("param: {:?}", param), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ StaticRef { alloc_id, ty, def_id } => {
+ print_indented!(self, "StaticRef {", depth_lvl);
+ print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+ print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ InlineAsm(expr) => {
+ print_indented!(self, "InlineAsm {", depth_lvl);
+ print_indented!(self, "expr:", depth_lvl + 1);
+ self.print_inline_asm_expr(&**expr, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ ThreadLocalRef(def_id) => {
+ print_indented!(self, "ThreadLocalRef {", depth_lvl);
+ print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+ Yield { value } => {
+ print_indented!(self, "Yield {", depth_lvl);
+ print_indented!(self, "value:", depth_lvl + 1);
+ self.print_expr(*value, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
+ }
+ }
+
+ fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) {
+ print_indented!(self, "adt_def:", depth_lvl);
+ self.print_adt_def(adt_expr.adt_def, depth_lvl + 1);
+ print_indented!(
+ self,
+ format!("variant_index: {:?}", adt_expr.variant_index),
+ depth_lvl + 1
+ );
+ print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1);
+ print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1);
+
+ for (i, field_expr) in adt_expr.fields.iter().enumerate() {
+ print_indented!(self, format!("field {}:", i), depth_lvl + 1);
+ self.print_expr(field_expr.expr, depth_lvl + 2);
+ }
+
+ if let Some(ref base) = adt_expr.base {
+ print_indented!(self, "base:", depth_lvl + 1);
+ self.print_fru_info(base, depth_lvl + 2);
+ } else {
+ print_indented!(self, "base: None", depth_lvl + 1);
+ }
+ }
+
+ fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) {
+ print_indented!(self, "AdtDef {", depth_lvl);
+ print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1);
+ print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1);
+ print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1);
+ print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1);
+ }
+
+ fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) {
+ print_indented!(self, "FruInfo {", depth_lvl);
+ print_indented!(self, "base: ", depth_lvl + 1);
+ self.print_expr(fru_info.base, depth_lvl + 2);
+ print_indented!(self, "field_types: [", depth_lvl + 1);
+ for ty in fru_info.field_types.iter() {
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+ }
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) {
+ print_indented!(self, "Arm {", depth_lvl);
+
+ let arm = &self.thir.arms[arm_id];
+ let Arm { pattern, guard, body, lint_level, scope, span } = arm;
+
+ print_indented!(self, "pattern: ", depth_lvl + 1);
+ self.print_pat(pattern, depth_lvl + 2);
+
+ if let Some(guard) = guard {
+ print_indented!(self, "guard: ", depth_lvl + 1);
+ self.print_guard(guard, depth_lvl + 2);
+ } else {
+ print_indented!(self, "guard: None", depth_lvl + 1);
+ }
+
+ print_indented!(self, "body: ", depth_lvl + 1);
+ self.print_expr(*body, depth_lvl + 2);
+ print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1);
+ print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) {
+ let Pat { ty, span, kind } = &**pat;
+
+ print_indented!(self, "Pat: {", depth_lvl);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ self.print_pat_kind(kind, depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
+ print_indented!(self, "kind: PatKind {", depth_lvl);
+
+ match pat_kind {
+ PatKind::Wild => {
+ print_indented!(self, "Wild", depth_lvl + 1);
+ }
+ PatKind::AscribeUserType { ascription, subpattern } => {
+ print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
+ print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
+ print_indented!(self, "subpattern: ", depth_lvl + 2);
+ self.print_pat(subpattern, depth_lvl + 3);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => {
+ print_indented!(self, "Binding {", depth_lvl + 1);
+ print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2);
+ print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
+ print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2);
+ print_indented!(self, format!("var: {:?}", var), depth_lvl + 2);
+ print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2);
+ print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2);
+
+ if let Some(subpattern) = subpattern {
+ print_indented!(self, "subpattern: Some( ", depth_lvl + 2);
+ self.print_pat(subpattern, depth_lvl + 3);
+ print_indented!(self, ")", depth_lvl + 2);
+ } else {
+ print_indented!(self, "subpattern: None", depth_lvl + 2);
+ }
+
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Variant { adt_def, substs, variant_index, subpatterns } => {
+ print_indented!(self, "Variant {", depth_lvl + 1);
+ print_indented!(self, "adt_def: ", depth_lvl + 2);
+ self.print_adt_def(*adt_def, depth_lvl + 3);
+ print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2);
+ print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2);
+
+ if subpatterns.len() > 0 {
+ print_indented!(self, "subpatterns: [", depth_lvl + 2);
+ for field_pat in subpatterns.iter() {
+ self.print_pat(&field_pat.pattern, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+ } else {
+ print_indented!(self, "subpatterns: []", depth_lvl + 2);
+ }
+
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Leaf { subpatterns } => {
+ print_indented!(self, "Leaf { ", depth_lvl + 1);
+ print_indented!(self, "subpatterns: [", depth_lvl + 2);
+ for field_pat in subpatterns.iter() {
+ self.print_pat(&field_pat.pattern, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Deref { subpattern } => {
+ print_indented!(self, "Deref { ", depth_lvl + 1);
+ print_indented!(self, "subpattern: ", depth_lvl + 2);
+ self.print_pat(subpattern, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Constant { value } => {
+ print_indented!(self, "Constant {", depth_lvl + 1);
+ print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Range(pat_range) => {
+ print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
+ }
+ PatKind::Slice { prefix, slice, suffix } => {
+ print_indented!(self, "Slice {", depth_lvl + 1);
+
+ print_indented!(self, "prefix: [", depth_lvl + 2);
+ for prefix_pat in prefix.iter() {
+ self.print_pat(prefix_pat, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+
+ if let Some(slice) = slice {
+ print_indented!(self, "slice: ", depth_lvl + 2);
+ self.print_pat(slice, depth_lvl + 3);
+ }
+
+ print_indented!(self, "suffix: [", depth_lvl + 2);
+ for suffix_pat in suffix.iter() {
+ self.print_pat(suffix_pat, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Array { prefix, slice, suffix } => {
+ print_indented!(self, "Array {", depth_lvl + 1);
+
+ print_indented!(self, "prefix: [", depth_lvl + 2);
+ for prefix_pat in prefix.iter() {
+ self.print_pat(prefix_pat, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+
+ if let Some(slice) = slice {
+ print_indented!(self, "slice: ", depth_lvl + 2);
+ self.print_pat(slice, depth_lvl + 3);
+ }
+
+ print_indented!(self, "suffix: [", depth_lvl + 2);
+ for suffix_pat in suffix.iter() {
+ self.print_pat(suffix_pat, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ PatKind::Or { pats } => {
+ print_indented!(self, "Or {", depth_lvl + 1);
+ print_indented!(self, "pats: [", depth_lvl + 2);
+ for pat in pats.iter() {
+ self.print_pat(pat, depth_lvl + 3);
+ }
+ print_indented!(self, "]", depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) {
+ print_indented!(self, "Guard {", depth_lvl);
+
+ match guard {
+ Guard::If(expr_id) => {
+ print_indented!(self, "If (", depth_lvl + 1);
+ self.print_expr(*expr_id, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl + 1);
+ }
+ Guard::IfLet(pat, expr_id) => {
+ print_indented!(self, "IfLet (", depth_lvl + 1);
+ self.print_pat(pat, depth_lvl + 2);
+ print_indented!(self, ",", depth_lvl + 1);
+ self.print_expr(*expr_id, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl + 1);
+ }
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) {
+ let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr;
+
+ print_indented!(self, "ClosureExpr {", depth_lvl);
+ print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1);
+ print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1);
+
+ if upvars.len() > 0 {
+ print_indented!(self, "upvars: [", depth_lvl + 1);
+ for upvar in upvars.iter() {
+ self.print_expr(*upvar, depth_lvl + 2);
+ print_indented!(self, ",", depth_lvl + 1);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ } else {
+ print_indented!(self, "upvars: []", depth_lvl + 1);
+ }
+
+ print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1);
+
+ if fake_reads.len() > 0 {
+ print_indented!(self, "fake_reads: [", depth_lvl + 1);
+ for (fake_read_expr, cause, hir_id) in fake_reads.iter() {
+ print_indented!(self, "(", depth_lvl + 2);
+ self.print_expr(*fake_read_expr, depth_lvl + 3);
+ print_indented!(self, ",", depth_lvl + 2);
+ print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3);
+ print_indented!(self, ",", depth_lvl + 2);
+ print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3);
+ print_indented!(self, "),", depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+ } else {
+ print_indented!(self, "fake_reads: []", depth_lvl + 1);
+ }
+
+ print_indented!(self, "}", depth_lvl);
+ }
+
+ fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) {
+ let InlineAsmExpr { template, operands, options, line_spans } = expr;
+
+ print_indented!(self, "InlineAsmExpr {", depth_lvl);
+
+ print_indented!(self, "template: [", depth_lvl + 1);
+ for template_piece in template.iter() {
+ print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+
+ print_indented!(self, "operands: [", depth_lvl + 1);
+ for operand in operands.iter() {
+ self.print_inline_operand(operand, depth_lvl + 2);
+ }
+ print_indented!(self, "]", depth_lvl + 1);
+
+ print_indented!(self, format!("options: {:?}", options), depth_lvl + 1);
+ print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1);
+ }
+
+ fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) {
+ match operand {
+ InlineAsmOperand::In { reg, expr } => {
+ print_indented!(self, "InlineAsmOperand::In {", depth_lvl);
+ print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+ print_indented!(self, "expr: ", depth_lvl + 1);
+ self.print_expr(*expr, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::Out { reg, late, expr } => {
+ print_indented!(self, "InlineAsmOperand::Out {", depth_lvl);
+ print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+ print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+
+ if let Some(out) = expr {
+ print_indented!(self, "place: Some( ", depth_lvl + 1);
+ self.print_expr(*out, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl + 1);
+ } else {
+ print_indented!(self, "place: None", depth_lvl + 1);
+ }
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::InOut { reg, late, expr } => {
+ print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl);
+ print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+ print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+ print_indented!(self, "expr: ", depth_lvl + 1);
+ self.print_expr(*expr, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
+ print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl);
+ print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1);
+ print_indented!(self, format!("late: {:?}", late), depth_lvl + 1);
+ print_indented!(self, "in_expr: ", depth_lvl + 1);
+ self.print_expr(*in_expr, depth_lvl + 2);
+
+ if let Some(out_expr) = out_expr {
+ print_indented!(self, "out_expr: Some( ", depth_lvl + 1);
+ self.print_expr(*out_expr, depth_lvl + 2);
+ print_indented!(self, ")", depth_lvl + 1);
+ } else {
+ print_indented!(self, "out_expr: None", depth_lvl + 1);
+ }
+
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::Const { value, span } => {
+ print_indented!(self, "InlineAsmOperand::Const {", depth_lvl);
+ print_indented!(self, format!("value: {:?}", value), depth_lvl + 1);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::SymFn { value, span } => {
+ print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl);
+ print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ InlineAsmOperand::SymStatic { def_id } => {
+ print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl);
+ print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl + 1);
+ }
+ }
+ }
+}
use std::mem;
use std::ops::{Bound, Deref};
+const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
+
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
}
pub fn const_eval_limit(self) -> Limit {
- self.limits(()).const_eval_limit
+ if self.sess.opts.unstable_opts.tiny_const_eval_limit {
+ TINY_CONST_EVAL_LIMIT
+ } else {
+ self.limits(()).const_eval_limit
+ }
}
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
}
}
- pub fn is_object_safe(self, key: DefId) -> bool {
- self.object_safety_violations(key).is_empty()
- }
-
#[inline]
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
matches!(
let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
let generator_kind = tcx.generator_kind(fn_def.did);
+ // The representation of thir for `-Zunpretty=thir-tree` relies on
+ // the entry expression being the last element of `thir.exprs`.
+ assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
+
// Figure out what primary body this item has.
let body_id = tcx.hir().body_owned_by(fn_def.did);
let span_with_body = tcx.hir().span_with_body(fn_id);
providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
providers.thir_body = thir::cx::thir_body;
providers.thir_tree = thir::cx::thir_tree;
+ providers.thir_flat = thir::cx::thir_flat;
}
}
pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+ match thir_body(tcx, owner_def) {
+ Ok((thir, _)) => {
+ let thir = thir.steal();
+ tcx.thir_tree_representation(&thir)
+ }
+ Err(_) => "error".into(),
+ }
+}
+
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
match thir_body(tcx, owner_def) {
Ok((thir, _)) => format!("{:#?}", thir.steal()),
Err(_) => "error".into(),
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => None,
};
if let Some(destination) = destination {
StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::FakeRead(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop
| StatementKind::Retag(..)
| StatementKind::Intrinsic(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
}
StatementKind::Retag(..) => {
// We don't track references.
}
- StatementKind::Nop
+ StatementKind::ConstEvalCounter
+ | StatementKind::Nop
| StatementKind::FakeRead(..)
| StatementKind::Coverage(..)
| StatementKind::AscribeUserType(..) => (),
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}
--- /dev/null
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::borrowed_locals;
+
+use crate::ssa::SsaLocals;
+use crate::MirPass;
+
+/// Unify locals that copy each other.
+///
+/// We consider patterns of the form
+/// _a = rvalue
+/// _b = move? _a
+/// _c = move? _a
+/// _d = move? _c
+/// where each of the locals is only assigned once.
+///
+/// We want to replace all those locals by `_a`, either copied or moved.
+pub struct CopyProp;
+
+impl<'tcx> MirPass<'tcx> for CopyProp {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
+ #[instrument(level = "trace", skip(self, tcx, body))]
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ debug!(def_id = ?body.source.def_id());
+ propagate_ssa(tcx, body);
+ }
+}
+
+fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let borrowed_locals = borrowed_locals(body);
+ let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
+
+ let fully_moved = fully_moved_locals(&ssa, body);
+ debug!(?fully_moved);
+
+ let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
+ for (local, &head) in ssa.copy_classes().iter_enumerated() {
+ if local != head {
+ storage_to_remove.insert(head);
+ }
+ }
+
+ let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
+
+ Replacer {
+ tcx,
+ copy_classes: &ssa.copy_classes(),
+ fully_moved,
+ borrowed_locals,
+ storage_to_remove,
+ }
+ .visit_body_preserves_cfg(body);
+
+ if any_replacement {
+ crate::simplify::remove_unused_definitions(body);
+ }
+}
+
+/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
+///
+/// This function also returns whether all the `move?` in the pattern are `move` and not copies.
+/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be
+/// replaced by `copy _a`, as we cannot move multiple times from `_a`.
+///
+/// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB.
+/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is
+/// moved, and therefore that `_d` is moved.
+#[instrument(level = "trace", skip(ssa, body))]
+fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
+ let mut fully_moved = BitSet::new_filled(body.local_decls.len());
+
+ for (_, rvalue) in ssa.assignments(body) {
+ let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+ = rvalue
+ else { continue };
+
+ let Some(rhs) = place.as_local() else { continue };
+ if !ssa.is_ssa(rhs) {
+ continue;
+ }
+
+ if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue {
+ fully_moved.remove(rhs);
+ }
+ }
+
+ ssa.meet_copy_equivalence(&mut fully_moved);
+
+ fully_moved
+}
+
+/// Utility to help performing subtitution of `*pattern` by `target`.
+struct Replacer<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ fully_moved: BitSet<Local>,
+ storage_to_remove: BitSet<Local>,
+ borrowed_locals: BitSet<Local>,
+ copy_classes: &'a IndexVec<Local, Local>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
+ let new_local = self.copy_classes[*local];
+ match ctxt {
+ // Do not modify the local in storage statements.
+ PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
+ // The local should have been marked as non-SSA.
+ PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local),
+ // We access the value.
+ _ => *local = new_local,
+ }
+ }
+
+ fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+ if let Some(new_projection) = self.process_projection(&place.projection, loc) {
+ place.projection = self.tcx().intern_place_elems(&new_projection);
+ }
+
+ let observes_address = match ctxt {
+ PlaceContext::NonMutatingUse(
+ NonMutatingUseContext::SharedBorrow
+ | NonMutatingUseContext::ShallowBorrow
+ | NonMutatingUseContext::UniqueBorrow
+ | NonMutatingUseContext::AddressOf,
+ ) => true,
+ // For debuginfo, merging locals is ok.
+ PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
+ self.borrowed_locals.contains(place.local)
+ }
+ _ => false,
+ };
+ if observes_address && !place.is_indirect() {
+ // We observe the address of `place.local`. Do not replace it.
+ } else {
+ self.visit_local(
+ &mut place.local,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+ loc,
+ )
+ }
+ }
+
+ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+ if let Operand::Move(place) = *operand
+ && let Some(local) = place.as_local()
+ && !self.fully_moved.contains(local)
+ {
+ *operand = Operand::Copy(place);
+ }
+ self.super_operand(operand, loc);
+ }
+
+ fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
+ if let StatementKind::StorageDead(l) = stmt.kind
+ && self.storage_to_remove.contains(l)
+ {
+ stmt.make_nop();
+ } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind
+ && place.as_local().is_some()
+ {
+ // Do not replace assignments.
+ self.visit_rvalue(rvalue, loc)
+ } else {
+ self.super_statement(stmt, loc);
+ }
+ }
+}
| StatementKind::StorageDead(_)
// Coverage should not be encountered, but don't inject coverage coverage
| StatementKind::Coverage(_)
+ // Ignore `ConstEvalCounter`s
+ | StatementKind::ConstEvalCounter
// Ignore `Nop`s
| StatementKind::Nop => None,
--- /dev/null
+//! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge
+//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
+use crate::MirPass;
+
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_middle::mir::{
+ BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
+};
+use rustc_middle::ty::TyCtxt;
+
+pub struct CtfeLimit;
+
+impl<'tcx> 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();
+ let indices: Vec<BasicBlock> = body
+ .basic_blocks
+ .iter_enumerated()
+ .filter_map(|(node, node_data)| {
+ if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
+ // Back edges in a CFG indicate loops
+ || has_back_edge(&doms, node, &node_data)
+ {
+ Some(node)
+ } else {
+ None
+ }
+ })
+ .collect();
+ for index in indices {
+ insert_counter(
+ body.basic_blocks_mut()
+ .get_mut(index)
+ .expect("basic_blocks index {index} should exist"),
+ );
+ }
+ }
+}
+
+fn has_back_edge(
+ doms: &Dominators<BasicBlock>,
+ node: BasicBlock,
+ node_data: &BasicBlockData<'_>,
+) -> bool {
+ if !doms.is_reachable(node) {
+ return false;
+ }
+ // Check if any of the dominators of the node are also the node's successor.
+ doms.dominators(node)
+ .any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom))
+}
+
+fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
+ basic_block_data.statements.push(Statement {
+ source_info: basic_block_data.terminator().source_info,
+ kind: StatementKind::ConstEvalCounter,
+ });
+}
| StatementKind::StorageDead(_)
| StatementKind::Coverage(_)
| StatementKind::Intrinsic(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => (),
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
match &statement.kind {
StatementKind::Assign(box (dest, rvalue)) => {
match rvalue {
- Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
+ Rvalue::CopyForDeref(place)
+ | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
// These might've been turned into self-assignments by the replacement
// (this includes the original statement we wanted to eliminate).
if dest == place {
self.add_place(**place);
}
StatementKind::Intrinsic(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop
| StatementKind::Coverage(_)
| StatementKind::StorageLive(_)
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
if let StatementKind::Assign(box (
lhs,
- Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
+ Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
)) = &statement.kind
{
let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
tcx: TyCtxt<'tcx>,
def_id: DefId,
) -> GeneratorLayout<'tcx> {
+ assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
let def_id = def_id.expect_local();
let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id));
let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
// Get the interior types and substs which typeck computed
- let (upvars, interior, movable) = match *gen_ty.kind() {
- ty::Generator(_, substs, movability) => {
- let substs = substs.as_generator();
- (
- substs.upvar_tys().collect::<Vec<_>>(),
- substs.witness(),
- movability == hir::Movability::Movable,
- )
- }
+ let movable = match *gen_ty.kind() {
+ ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
_ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
};
// `storage_liveness` tells us which locals have live storage at suspension points
let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body);
- if tcx.sess.opts.unstable_opts.drop_tracking_mir {
- check_suspend_tys(tcx, &generator_layout, &body);
- } else {
- sanitize_witness(tcx, body, interior, upvars, &generator_layout);
- }
+ check_suspend_tys(tcx, &generator_layout, &body);
generator_layout
}
let gen_ty = body.local_decls.raw[1].ty;
// Get the discriminant type and substs which typeck computed
- let (discr_ty, movable) = match *gen_ty.kind() {
+ let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() {
ty::Generator(_, substs, movability) => {
let substs = substs.as_generator();
- (substs.discr_ty(tcx), movability == hir::Movability::Movable)
+ (
+ substs.discr_ty(tcx),
+ substs.upvar_tys().collect::<Vec<_>>(),
+ substs.witness(),
+ movability == hir::Movability::Movable,
+ )
}
_ => {
tcx.sess
// `storage_liveness` tells us which locals have live storage at suspension points
let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body);
+ if tcx.sess.opts.unstable_opts.validate_mir
+ && !tcx.sess.opts.unstable_opts.drop_tracking_mir
+ {
+ sanitize_witness(tcx, body, interior, upvars, &layout);
+ }
+
let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
// Run the transformation which converts Places from Local to generator struct
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
}
mod const_goto;
mod const_prop;
mod const_prop_lint;
+mod copy_prop;
mod coverage;
+mod ctfe_limit;
mod dataflow_const_prop;
mod dead_store_elimination;
mod deaggregator;
mod reveal_all;
mod separate_const_switch;
mod shim;
+mod ssa;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod simplify;
mod simplify_branches;
}
}
+ pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
+
debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
body
return tcx.mir_drops_elaborated_and_const_checked(def);
}
- if tcx.generator_kind(def.did).is_some() {
+ if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir {
tcx.ensure().mir_generator_witnesses(def.did);
}
let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
&instcombine::InstCombine,
&separate_const_switch::SeparateConstSwitch,
&simplify::SimplifyLocals::new("before-const-prop"),
+ ©_prop::CopyProp,
//
// FIXME(#70073): This pass is responsible for both optimization as well as some lints.
&const_prop::ConstProp,
| StatementKind::StorageDead(_)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {
// These are all noops in a landing pad
}
| StatementKind::Coverage(_)
| StatementKind::StorageDead(_)
| StatementKind::Intrinsic(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
}
}
| StatementKind::AscribeUserType(_, _)
| StatementKind::Coverage(_)
| StatementKind::Intrinsic(_)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
// If the discriminant is set, it is always set
}
}
+pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
+ // First, we're going to get a count of *actual* uses for every `Local`.
+ let mut used_locals = UsedLocals::new(body);
+
+ // Next, we're going to remove any `Local` with zero actual uses. When we remove those
+ // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
+ // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
+ // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
+ // fixedpoint where there are no more unused locals.
+ remove_unused_definitions_helper(&mut used_locals, body);
+}
+
pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
// First, we're going to get a count of *actual* uses for every `Local`.
let mut used_locals = UsedLocals::new(body);
// count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
// `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
// fixedpoint where there are no more unused locals.
- remove_unused_definitions(&mut used_locals, body);
+ remove_unused_definitions_helper(&mut used_locals, body);
// Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
let map = make_local_map(&mut body.local_decls, &used_locals);
self.super_statement(statement, location);
}
- StatementKind::Nop => {}
+ StatementKind::ConstEvalCounter | StatementKind::Nop => {}
StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
}
/// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
+fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
// The use counts are updated as we remove the statements. A local might become unused
// during the retain operation, leading to a temporary inconsistency (storage statements or
// definitions referencing the local might remain). For correctness it is crucial that this
--- /dev/null
+use either::Either;
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::middle::resolve_lifetime::Set1;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
+
+#[derive(Debug)]
+pub struct SsaLocals {
+ /// Assignments to each local. This defines whether the local is SSA.
+ assignments: IndexVec<Local, Set1<LocationExtended>>,
+ /// We visit the body in reverse postorder, to ensure each local is assigned before it is used.
+ /// We remember the order in which we saw the assignments to compute the SSA values in a single
+ /// pass.
+ assignment_order: Vec<Local>,
+ /// Copy equivalence classes between locals. See `copy_classes` for documentation.
+ copy_classes: IndexVec<Local, Local>,
+}
+
+impl SsaLocals {
+ pub fn new<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ body: &Body<'tcx>,
+ borrowed_locals: &BitSet<Local>,
+ ) -> SsaLocals {
+ let assignment_order = Vec::new();
+
+ let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
+ let dominators = body.basic_blocks.dominators();
+ let mut visitor = SsaVisitor { assignments, assignment_order, dominators };
+
+ for (local, decl) in body.local_decls.iter_enumerated() {
+ if matches!(body.local_kind(local), LocalKind::Arg) {
+ visitor.assignments[local] = Set1::One(LocationExtended::Arg);
+ }
+ if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) {
+ visitor.assignments[local] = Set1::Many;
+ }
+ }
+
+ for (bb, data) in traversal::reverse_postorder(body) {
+ visitor.visit_basic_block_data(bb, data);
+ }
+
+ for var_debug_info in &body.var_debug_info {
+ visitor.visit_var_debug_info(var_debug_info);
+ }
+
+ debug!(?visitor.assignments);
+
+ visitor
+ .assignment_order
+ .retain(|&local| matches!(visitor.assignments[local], Set1::One(_)));
+ debug!(?visitor.assignment_order);
+
+ let copy_classes = compute_copy_classes(&visitor, body);
+
+ SsaLocals {
+ assignments: visitor.assignments,
+ assignment_order: visitor.assignment_order,
+ copy_classes,
+ }
+ }
+
+ pub fn is_ssa(&self, local: Local) -> bool {
+ matches!(self.assignments[local], Set1::One(_))
+ }
+
+ pub fn assignments<'a, 'tcx>(
+ &'a self,
+ body: &'a Body<'tcx>,
+ ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>)> + 'a {
+ self.assignment_order.iter().filter_map(|&local| {
+ if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
+ // `loc` must point to a direct assignment to `local`.
+ let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+ let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+ assert_eq!(target.as_local(), Some(local));
+ Some((local, rvalue))
+ } else {
+ None
+ }
+ })
+ }
+
+ /// Compute the equivalence classes for locals, based on copy statements.
+ ///
+ /// The returned vector maps each local to the one it copies. In the following case:
+ /// _a = &mut _0
+ /// _b = move? _a
+ /// _c = move? _a
+ /// _d = move? _c
+ /// We return the mapping
+ /// _a => _a // not a copy so, represented by itself
+ /// _b => _a
+ /// _c => _a
+ /// _d => _a // transitively through _c
+ ///
+ /// Exception: we do not see through the return place, as it cannot be substituted.
+ pub fn copy_classes(&self) -> &IndexVec<Local, Local> {
+ &self.copy_classes
+ }
+
+ /// Make a property uniform on a copy equivalence class by removing elements.
+ pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
+ // Consolidate to have a local iff all its copies are.
+ //
+ // `copy_classes` defines equivalence classes between locals. The `local`s that recursively
+ // move/copy the same local all have the same `head`.
+ for (local, &head) in self.copy_classes.iter_enumerated() {
+ // If any copy does not have `property`, then the head is not.
+ if !property.contains(local) {
+ property.remove(head);
+ }
+ }
+ for (local, &head) in self.copy_classes.iter_enumerated() {
+ // If any copy does not have `property`, then the head doesn't either,
+ // then no copy has `property`.
+ if !property.contains(head) {
+ property.remove(local);
+ }
+ }
+
+ // Verify that we correctly computed equivalence classes.
+ #[cfg(debug_assertions)]
+ for (local, &head) in self.copy_classes.iter_enumerated() {
+ assert_eq!(property.contains(local), property.contains(head));
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum LocationExtended {
+ Plain(Location),
+ Arg,
+}
+
+struct SsaVisitor {
+ dominators: Dominators<BasicBlock>,
+ assignments: IndexVec<Local, Set1<LocationExtended>>,
+ assignment_order: Vec<Local>,
+}
+
+impl<'tcx> Visitor<'tcx> for SsaVisitor {
+ fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
+ match ctxt {
+ PlaceContext::MutatingUse(MutatingUseContext::Store) => {
+ self.assignments[local].insert(LocationExtended::Plain(loc));
+ self.assignment_order.push(local);
+ }
+ // Anything can happen with raw pointers, so remove them.
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
+ | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many,
+ // Immutable borrows are taken into account in `SsaLocals::new` by
+ // removing non-freeze locals.
+ PlaceContext::NonMutatingUse(_) => {
+ let set = &mut self.assignments[local];
+ let assign_dominates = match *set {
+ Set1::Empty | Set1::Many => false,
+ Set1::One(LocationExtended::Arg) => true,
+ Set1::One(LocationExtended::Plain(assign)) => {
+ assign.successor_within_block().dominates(loc, &self.dominators)
+ }
+ };
+ // We are visiting a use that is not dominated by an assignment.
+ // Either there is a cycle involved, or we are reading for uninitialized local.
+ // Bail out.
+ if !assign_dominates {
+ *set = Set1::Many;
+ }
+ }
+ PlaceContext::NonUse(_) => {}
+ }
+ }
+}
+
+#[instrument(level = "trace", skip(ssa, body))]
+fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> {
+ let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
+
+ for &local in &ssa.assignment_order {
+ debug!(?local);
+
+ if local == RETURN_PLACE {
+ // `_0` is special, we cannot rename it.
+ continue;
+ }
+
+ // This is not SSA: mark that we don't know the value.
+ debug!(assignments = ?ssa.assignments[local]);
+ let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue };
+
+ // `loc` must point to a direct assignment to `local`.
+ let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
+ let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() };
+ assert_eq!(_target.as_local(), Some(local));
+
+ let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
+ = rvalue
+ else { continue };
+
+ let Some(rhs) = place.as_local() else { continue };
+ let Set1::One(_) = ssa.assignments[rhs] else { continue };
+
+ // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
+ // visited before `local`, and we just have to copy the representing local.
+ copies[local] = copies[rhs];
+ }
+
+ debug!(?copies);
+
+ // Invariant: `copies` must point to the head of an equivalence class.
+ #[cfg(debug_assertions)]
+ for &head in copies.iter() {
+ assert_eq!(copies[head], head);
+ }
+
+ copies
+}
pub sub: MatchArmBodyWithoutBracesSugg,
}
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_extra_equals)]
+#[note]
+pub(crate) struct InclusiveRangeExtraEquals {
+ #[primary_span]
+ #[suggestion(
+ suggestion_remove_eq,
+ style = "short",
+ code = "..=",
+ applicability = "maybe-incorrect"
+ )]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_match_arrow)]
+pub(crate) struct InclusiveRangeMatchArrow {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(
+ suggestion_add_space,
+ style = "verbose",
+ code = " ",
+ applicability = "machine-applicable"
+ )]
+ pub after_pat: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_no_end, code = "E0586")]
+#[note]
+pub(crate) struct InclusiveRangeNoEnd {
+ #[primary_span]
+ #[suggestion(
+ suggestion_open_range,
+ code = "..",
+ applicability = "machine-applicable",
+ style = "short"
+ )]
+ pub span: Span,
+}
+
#[derive(Subdiagnostic)]
pub(crate) enum MatchArmBodyWithoutBracesSugg {
#[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
limits: RangeLimits,
) -> ExprKind {
if end.is_none() && limits == RangeLimits::Closed {
- self.inclusive_range_with_incorrect_end(self.prev_token.span);
+ self.inclusive_range_with_incorrect_end();
ExprKind::Err
} else {
ExprKind::Range(start, end, limits)
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::errors::RemoveLet;
+use crate::errors::{
+ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
+};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
// Parsing e.g. `X..`.
if let RangeEnd::Included(_) = re.node {
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
- self.inclusive_range_with_incorrect_end(re.span);
+ self.inclusive_range_with_incorrect_end();
}
None
};
Ok(PatKind::Range(Some(begin), end, re))
}
- pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
+ pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
let tok = &self.token;
-
+ let span = self.prev_token.span;
// If the user typed "..==" instead of "..=", we want to give them
// a specific error message telling them to use "..=".
+ // If they typed "..=>", suggest they use ".. =>".
// Otherwise, we assume that they meant to type a half open exclusive
// range and give them an error telling them to do that instead.
- if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
- let span_with_eq = span.to(tok.span);
+ let no_space = tok.span.lo() == span.hi();
+ match tok.kind {
+ token::Eq if no_space => {
+ let span_with_eq = span.to(tok.span);
- // Ensure the user doesn't receive unhelpful unexpected token errors
- self.bump();
- if self.is_pat_range_end_start(0) {
- let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
- }
+ // Ensure the user doesn't receive unhelpful unexpected token errors
+ self.bump();
+ if self.is_pat_range_end_start(0) {
+ let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
+ }
- self.error_inclusive_range_with_extra_equals(span_with_eq);
- } else {
- self.error_inclusive_range_with_no_end(span);
+ self.error_inclusive_range_with_extra_equals(span_with_eq);
+ }
+ token::Gt if no_space => {
+ self.error_inclusive_range_match_arrow(span);
+ }
+ _ => self.error_inclusive_range_with_no_end(span),
}
}
fn error_inclusive_range_with_extra_equals(&self, span: Span) {
- self.struct_span_err(span, "unexpected `=` after inclusive range")
- .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
- .note("inclusive ranges end with a single equals sign (`..=`)")
- .emit();
+ self.sess.emit_err(InclusiveRangeExtraEquals { span });
+ }
+
+ fn error_inclusive_range_match_arrow(&self, span: Span) {
+ let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+ self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
}
fn error_inclusive_range_with_no_end(&self, span: Span) {
- struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
- .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
- .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
- .emit();
+ self.sess.emit_err(InclusiveRangeNoEnd { span });
}
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
self.parse_remaining_bounds(bounds, true)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
let sp = vec![lo, self.prev_token.span];
- let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+ let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())];
self.struct_span_err(sp, "incorrect braces around trait bounds")
.multipart_suggestion(
"remove the parentheses",
"hir,typed" => Hir(PpHirMode::Typed),
"hir-tree" => HirTree,
"thir-tree" => ThirTree,
+ "thir-flat" => ThirFlat,
"mir" => Mir,
"mir-cfg" => MirCFG,
name => early_error(
"argument to `unpretty` must be one of `normal`, `identified`, \
`expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
- `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
+ `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
+ `mir-cfg`; got {name}"
),
),
};
HirTree,
/// `-Zunpretty=thir-tree`
ThirTree,
+ /// `-Zunpretty=`thir-flat`
+ ThirFlat,
/// `-Zunpretty=mir`
Mir,
/// `-Zunpretty=mir-cfg`
| Hir(_)
| HirTree
| ThirTree
+ | ThirFlat
| Mir
| MirCFG => true,
}
match *self {
Source(_) | AstTree(_) => false,
- Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
+ Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true,
}
}
pub fn needs_analysis(&self) -> bool {
use PpMode::*;
- matches!(*self, Mir | MirCFG | ThirTree)
+ matches!(*self, Mir | MirCFG | ThirTree | ThirFlat)
}
}
"measure time of each LLVM pass (default: no)"),
time_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each rustc pass (default: no)"),
+ tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
+ "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
"choose the TLS model to use (`rustc --print tls-models` for details)"),
mul,
mul_assign,
mul_with_overflow,
+ multiple_supertrait_upcastable,
must_not_suspend,
must_use,
naked,
/// let _y = x.clone();
/// }
/// ```
- AliasBound(usize),
+ AliasBound,
}
pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
// NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
// This doesn't work as long as we use `CandidateSource` in winnowing.
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
- // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type
- // could be normalized to yet another projection with different item bounds.
let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
for mut normalized_candidate in normalized_candidates {
normalized_candidate.result =
ty::Alias(_, alias_ty) => alias_ty,
};
- for (i, (assumption, _)) in self
+ for (assumption, _) in self
.tcx()
.bound_explicit_item_bounds(alias_ty.def_id)
.subst_iter_copied(self.tcx(), alias_ty.substs)
- .enumerate()
{
match G::consider_assumption(self, goal, assumption) {
Ok(result) => {
- candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
+ candidates.push(Candidate { source: CandidateSource::AliasBound, result })
}
Err(NoSolution) => (),
}
// preserves universes and creates a unique var (in the highest universe) for each
// appearance of a region.
-// FIXME: `CanonicalVarValues` should be interned and `Copy`.
-
// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
use std::mem;
use rustc_hir::def_id::DefId;
-use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
let external_constraints = take_external_constraints(self.infcx)?;
Ok(self.infcx.canonicalize_response(Response {
- var_values: self.var_values.clone(),
+ var_values: self.var_values,
external_constraints,
certainty,
}))
}
fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
- if self.tcx().is_object_safe(trait_def_id) {
+ if self.tcx().check_is_object_safe(trait_def_id) {
self.make_canonical_response(Certainty::Yes)
} else {
Err(NoSolution)
goal: Canonical<'tcx, impl Sized>,
certainty: Certainty,
) -> QueryResult<'tcx> {
- let var_values = goal
- .variables
- .iter()
- .enumerate()
- .map(|(i, info)| match info.kind {
- CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
- tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
- }
- CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_usize(i),
- kind: ty::BrAnon(i as u32, None),
- };
- tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
- }
- CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
- .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
- .into(),
- })
- .collect();
-
Ok(Canonical {
max_universe: goal.max_universe,
variables: goal.variables,
value: Response {
- var_values: CanonicalVarValues { var_values },
+ var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
external_constraints: Default::default(),
certainty,
},
(CandidateSource::Impl(_), _)
| (CandidateSource::ParamEnv(_), _)
| (CandidateSource::BuiltinImpl, _)
- | (CandidateSource::AliasBound(_), _) => unimplemented!(),
+ | (CandidateSource::AliasBound, _) => unimplemented!(),
}
}
}
}
pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> {
+ // FIXME: Responses should probably be `Copy` as well
self.entries[entry_index].response.clone()
}
}
match (candidate.source, other.source) {
(CandidateSource::Impl(_), _)
| (CandidateSource::ParamEnv(_), _)
- | (CandidateSource::AliasBound(_), _)
+ | (CandidateSource::AliasBound, _)
| (CandidateSource::BuiltinImpl, _) => unimplemented!(),
}
}
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
predicates
.principal_def_id()
- .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
+ .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
}
// We only want to suggest `impl Trait` to `dyn Trait`s.
// For example, `fn foo() -> str` needs to be filtered out.
}
ty::PredicateKind::ObjectSafe(trait_def_id) => {
- if !self.selcx.tcx().is_object_safe(trait_def_id) {
+ if !self.selcx.tcx().check_is_object_safe(trait_def_id) {
ProcessResult::Error(CodeSelectionError(Unimplemented))
} else {
ProcessResult::Changed(vec![])
)
}
+fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+ let violations = tcx.object_safety_violations(trait_def_id);
+
+ if violations.is_empty() {
+ return true;
+ }
+
+ // If the trait contains any other violations, then let the error reporting path
+ // report it instead of emitting a warning here.
+ if violations.iter().all(|violation| {
+ matches!(
+ violation,
+ ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
+ )
+ }) {
+ for violation in violations {
+ if let ObjectSafetyViolation::Method(
+ _,
+ MethodViolationCode::WhereClauseReferencesSelf,
+ span,
+ ) = violation
+ {
+ lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
+ }
+ }
+ return true;
+ }
+
+ false
+}
+
/// We say a method is *vtable safe* if it can be invoked on a trait
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self: Sized` or
object_safety_violation_for_method(tcx, trait_def_id, &item)
.map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
})
- .filter(|violation| {
- if let ObjectSafetyViolation::Method(
- _,
- MethodViolationCode::WhereClauseReferencesSelf,
- span,
- ) = violation
- {
- lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
- false
- } else {
- true
- }
- })
.collect();
// Check the trait itself.
}
pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { object_safety_violations, ..*providers };
+ *providers =
+ ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
}
if let Some(principal) = data.principal() {
if !self.infcx.tcx.features().object_safe_for_dispatch {
principal.with_self_ty(self.tcx(), self_ty)
- } else if self.tcx().is_object_safe(principal.def_id()) {
+ } else if self.tcx().check_is_object_safe(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty)
} else {
return;
// `T` -> `Trait`
(_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
let mut object_dids = data.auto_traits().chain(data.principal_def_id());
- if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
+ if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) {
return Err(TraitNotObjectSafe(did));
}
}
ty::PredicateKind::ObjectSafe(trait_def_id) => {
- if self.tcx().is_object_safe(trait_def_id) {
+ if self.tcx().check_is_object_safe(trait_def_id) {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToErr)
}
fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
- self.interner.tcx.is_object_safe(trait_id.0)
+ self.interner.tcx.check_is_object_safe(trait_id.0)
}
fn hidden_opaque_type(
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::IndexVec;
-
use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
use rustc_middle::traits::ChalkRustInterner;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_infer::infer::canonical::{
Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
binders: chalk_ir::CanonicalVarKinds<_>| {
use rustc_middle::infer::canonical::CanonicalVarInfo;
- let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
- subst.as_slice(interner).iter().for_each(|p| {
- var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
- });
+ let var_values = tcx.mk_substs(
+ subst
+ .as_slice(interner)
+ .iter()
+ .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
+ );
let variables: Vec<_> = binders
.iter(interner)
.map(|var| {
max_universe: ty::UniverseIndex::from_usize(0),
variables: obligation.variables,
value: QueryResponse {
- var_values: CanonicalVarValues { var_values: IndexVec::new() }
- .make_identity(tcx),
+ var_values: CanonicalVarValues::dummy(),
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Ambiguous,
opaque_types: vec![],
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::Error;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::fmt::{write, ArgumentV1, Arguments};
+pub use core::fmt::{write, Arguments};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{Binary, Octal};
#[stable(feature = "rust1", since = "1.0.0")]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
//
// Library features:
#![feature(alloc_layout_extra)]
#![feature(c_unwind)]
#![feature(with_negative_coherence)]
#![cfg_attr(test, feature(panic_update_hook))]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
//
// Rustdoc features:
#![feature(doc_cfg)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
#[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
pub trait Error: Debug + Display {
/// The lower-level source of this error, if any.
///
#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
+#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
//
// Library features:
#![feature(const_align_offset)]
#![feature(unsized_fn_params)]
#![feature(asm_const)]
#![feature(const_transmute_copy)]
+#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
//
// Target features:
#![feature(arm_target_feature)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
+ #[rustc_allow_const_fn_unstable(const_cmp)]
pub const fn signum(self) -> Self {
- match self {
- n if n > 0 => 1,
- 0 => 0,
- _ => -1,
- }
+ // Picking the right way to phrase this is complicated
+ // (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>)
+ // so delegate it to `Ord` which is already producing -1/0/+1
+ // exactly like we need and can be the place to deal with the complexity.
+ self.cmp(&0) as _
}
/// Returns `true` if `self` is positive and `false` if the number is zero or
//! OS-specific networking functionality.
+// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must
+// be special-cased during rustdoc generation.
+#[cfg(not(all(
+ doc,
+ any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ all(target_vendor = "fortanix", target_env = "sgx")
+ )
+)))]
#[cfg(any(target_os = "linux", target_os = "android", doc))]
pub(super) mod linux_ext;
#[cfg(any(
target_arch = "x86",
target_arch = "arm",
+ target_arch = "m68k",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
//! Temporal quantification.
//!
-//! # Examples:
+//! # Examples
//!
//! There are multiple ways to create a new [`Duration`]:
//!
pub metrics: MetricMap,
pub failures: Vec<(TestDesc, Vec<u8>)>,
pub not_failures: Vec<(TestDesc, Vec<u8>)>,
+ pub ignores: Vec<(TestDesc, Vec<u8>)>,
pub time_failures: Vec<(TestDesc, Vec<u8>)>,
pub options: Options,
}
metrics: MetricMap::new(),
failures: Vec::new(),
not_failures: Vec::new(),
+ ignores: Vec::new(),
time_failures: Vec::new(),
options: opts.options,
})
st.passed += 1;
st.not_failures.push((test, stdout));
}
- TestResult::TrIgnored => st.ignored += 1,
+ TestResult::TrIgnored => {
+ st.ignored += 1;
+ st.ignores.push((test, stdout));
+ }
TestResult::TrBench(bs) => {
st.metrics.insert_metric(
test.name.as_slice(),
self.write_plain("\n\n")?;
+ // Custom handling of cases where there is only 1 test to execute and that test was ignored.
+ // We want to show more detailed information(why was the test ignored) for investigation purposes.
+ if self.total_test_count == 1 && state.ignores.len() == 1 {
+ let test_desc = &state.ignores[0].0;
+ if let Some(im) = test_desc.ignore_message {
+ self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?;
+ }
+ }
+
Ok(success)
}
}
failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
options: Options::new(),
not_failures: Vec::new(),
+ ignores: Vec::new(),
time_failures: Vec::new(),
};
use std::io;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::process::{Command, Stdio};
use std::str;
use build_helper::ci::CiEnv;
// Try passing `--progress` to start, then run git again without if that fails.
let update = |progress: bool| {
- let mut git = Command::new("git");
+ // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
+ // even though that has no relation to the upstream for the submodule.
+ let current_branch = {
+ let output = self
+ .config
+ .git()
+ .args(["symbolic-ref", "--short", "HEAD"])
+ .stderr(Stdio::inherit())
+ .output();
+ let output = t!(output);
+ if output.status.success() {
+ Some(String::from_utf8(output.stdout).unwrap().trim().to_owned())
+ } else {
+ None
+ }
+ };
+
+ let mut git = self.config.git();
+ if let Some(branch) = current_branch {
+ git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
+ }
git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]);
if progress {
git.arg("--progress");
}
- git.arg(relative_path).current_dir(&self.config.src);
+ git.arg(relative_path);
git
};
// NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
return Vec::new();
}
+ if !stamp.exists() {
+ eprintln!(
+ "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?",
+ stamp.display()
+ );
+ crate::detail_exit(1);
+ }
+
let mut paths = Vec::new();
let contents = t!(fs::read(stamp), &stamp);
// This is the method we use for extracting paths from the stamp file passed to us. See
--set rust.jemalloc \
--set rust.use-lld=true \
--set rust.lto=thin
-ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
+ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \
--host $HOSTS --target $HOSTS \
--include-default-paths \
build-manifest bootstrap
cd rust-toolstate
python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \
"$(git log --format=%s -n1 HEAD)" "" ""
-# Only check maintainers if this build is supposed to publish toolstate.
-# Builds that are not supposed to publish don't have the access token.
-if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
- TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \
- "../../src/tools/publish_toolstate.py"
-fi
cd ..
rm -rf rust-toolstate
- name: i686-mingw-1
env:
- RUST_CONFIGURE_ARGS: >-
- --build=i686-pc-windows-gnu
- --set llvm.allow-old-toolchain
+ RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
SCRIPT: make ci-mingw-subset-1
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
- name: i686-mingw-2
env:
- RUST_CONFIGURE_ARGS: >-
- --build=i686-pc-windows-gnu
- --set llvm.allow-old-toolchain
+ RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
SCRIPT: make ci-mingw-subset-2
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
RUST_CONFIGURE_ARGS: >-
--build=x86_64-pc-windows-gnu
--enable-profiler
- --set llvm.allow-old-toolchain
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
NO_DOWNLOAD_CI_LLVM: 1
RUST_CONFIGURE_ARGS: >-
--build=x86_64-pc-windows-gnu
--enable-profiler
- --set llvm.allow-old-toolchain
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
NO_DOWNLOAD_CI_LLVM: 1
--enable-full-tools
--enable-profiler
--set rust.lto=thin
- SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
+ SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
DIST_REQUIRE_ALL_TOOLS: 1
<<: *job-windows-xl
--build=i686-pc-windows-gnu
--enable-full-tools
--enable-profiler
- --set llvm.allow-old-toolchain
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
NO_DOWNLOAD_CI_LLVM: 1
--build=x86_64-pc-windows-gnu
--enable-full-tools
--enable-profiler
- --set llvm.allow-old-toolchain
# We are intentionally allowing an old toolchain on this builder (and that's
# incompatible with LLVM downloads today).
NO_DOWNLOAD_CI_LLVM: 1
# If we need to download a custom MinGW, do so here and set the path
# appropriately.
#
-# Here we also do a pretty heinous thing which is to mangle the MinGW
-# installation we just downloaded. Currently, as of this writing, we're using
-# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it
-# appears to be the first version which contains a fix for #40546, builds
-# randomly failing during LLVM due to ar.exe/ranlib.exe failures.
-#
-# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
-# to contain a regression in gdb (#40184). As a result if we were to use the
-# gdb provided (7.11.1) then we would fail all debuginfo tests.
-#
-# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
-# avoid disabling gdb tests we download an *old* version of gdb, specifically
-# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
-# with the 6.2.0 gdb to get tests passing.
-#
-# Note that we don't literally overwrite the gdb.exe binary because it appears
-# to just use gdborig.exe, so that's the binary we deal with instead.
-#
# Otherwise install MinGW through `pacman`
set -euo pipefail
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z"
-MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z"
+MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z"
+MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z"
if isWindows; then
case "${CI_JOB_NAME}" in
curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
7z x -y mingw.7z > /dev/null
- curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe"
ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
fi
fi
--- /dev/null
+#!/usr/bin/env python3
+# ignore-tidy-linelength
+
+# Compatible with Python 3.6+
+
+import contextlib
+import getpass
+import glob
+import logging
+import os
+import pprint
+import shutil
+import subprocess
+import sys
+import time
+import traceback
+import urllib.request
+from collections import OrderedDict
+from io import StringIO
+from pathlib import Path
+from typing import Callable, Dict, Iterable, List, Optional, Union
+
+PGO_HOST = os.environ["PGO_HOST"]
+
+LOGGER = logging.getLogger("stage-build")
+
+LLVM_PGO_CRATES = [
+ "syn-1.0.89",
+ "cargo-0.60.0",
+ "serde-1.0.136",
+ "ripgrep-13.0.0",
+ "regex-1.5.5",
+ "clap-3.1.6",
+ "hyper-0.14.18"
+]
+
+RUSTC_PGO_CRATES = [
+ "externs",
+ "ctfe-stress-5",
+ "cargo-0.60.0",
+ "token-stream-stress",
+ "match-stress",
+ "tuple-stress",
+ "diesel-1.4.8",
+ "bitmaps-3.1.0"
+]
+
+LLVM_BOLT_CRATES = LLVM_PGO_CRATES
+
+
+class Pipeline:
+ # Paths
+ def checkout_path(self) -> Path:
+ """
+ The root checkout, where the source is located.
+ """
+ raise NotImplementedError
+
+ def downloaded_llvm_dir(self) -> Path:
+ """
+ Directory where the host LLVM is located.
+ """
+ raise NotImplementedError
+
+ def build_root(self) -> Path:
+ """
+ The main directory where the build occurs.
+ """
+ raise NotImplementedError
+
+ def build_artifacts(self) -> Path:
+ return self.build_root() / "build" / PGO_HOST
+
+ def rustc_stage_0(self) -> Path:
+ return self.build_artifacts() / "stage0" / "bin" / "rustc"
+
+ def cargo_stage_0(self) -> Path:
+ return self.build_artifacts() / "stage0" / "bin" / "cargo"
+
+ def rustc_stage_2(self) -> Path:
+ return self.build_artifacts() / "stage2" / "bin" / "rustc"
+
+ def opt_artifacts(self) -> Path:
+ raise NotImplementedError
+
+ def llvm_profile_dir_root(self) -> Path:
+ return self.opt_artifacts() / "llvm-pgo"
+
+ def llvm_profile_merged_file(self) -> Path:
+ return self.opt_artifacts() / "llvm-pgo.profdata"
+
+ def rustc_perf_dir(self) -> Path:
+ return self.opt_artifacts() / "rustc-perf"
+
+ def build_rustc_perf(self):
+ raise NotImplementedError()
+
+ def rustc_profile_dir_root(self) -> Path:
+ return self.opt_artifacts() / "rustc-pgo"
+
+ def rustc_profile_merged_file(self) -> Path:
+ return self.opt_artifacts() / "rustc-pgo.profdata"
+
+ def rustc_profile_template_path(self) -> Path:
+ """
+ The profile data is written into a single filepath that is being repeatedly merged when each
+ rustc invocation ends. Empirically, this can result in some profiling data being lost. That's
+ why we override the profile path to include the PID. This will produce many more profiling
+ files, but the resulting profile will produce a slightly faster rustc binary.
+ """
+ return self.rustc_profile_dir_root() / "default_%m_%p.profraw"
+
+ def supports_bolt(self) -> bool:
+ raise NotImplementedError
+
+ def llvm_bolt_profile_merged_file(self) -> Path:
+ return self.opt_artifacts() / "bolt.profdata"
+
+
+class LinuxPipeline(Pipeline):
+ def checkout_path(self) -> Path:
+ return Path("/checkout")
+
+ def downloaded_llvm_dir(self) -> Path:
+ return Path("/rustroot")
+
+ def build_root(self) -> Path:
+ return self.checkout_path() / "obj"
+
+ def opt_artifacts(self) -> Path:
+ return Path("/tmp/tmp-multistage/opt-artifacts")
+
+ def build_rustc_perf(self):
+ # /tmp/rustc-perf comes from the Dockerfile
+ shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir())
+ cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()])
+
+ with change_cwd(self.rustc_perf_dir()):
+ cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict(
+ RUSTC=str(self.rustc_stage_0()),
+ RUSTC_BOOTSTRAP="1"
+ ))
+
+ def supports_bolt(self) -> bool:
+ return True
+
+
+class WindowsPipeline(Pipeline):
+ def __init__(self):
+ self.checkout_dir = Path(os.getcwd())
+
+ def checkout_path(self) -> Path:
+ return self.checkout_dir
+
+ def downloaded_llvm_dir(self) -> Path:
+ return self.checkout_path() / "citools" / "clang-rust"
+
+ def build_root(self) -> Path:
+ return self.checkout_path()
+
+ def opt_artifacts(self) -> Path:
+ return self.checkout_path() / "opt-artifacts"
+
+ def rustc_stage_0(self) -> Path:
+ return super().rustc_stage_0().with_suffix(".exe")
+
+ def cargo_stage_0(self) -> Path:
+ return super().cargo_stage_0().with_suffix(".exe")
+
+ def rustc_stage_2(self) -> Path:
+ return super().rustc_stage_2().with_suffix(".exe")
+
+ def build_rustc_perf(self):
+ # rustc-perf version from 2022-07-22
+ perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c"
+ rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"
+
+ def download_rustc_perf():
+ download_file(
+ f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip",
+ rustc_perf_zip_path
+ )
+ with change_cwd(self.opt_artifacts()):
+ unpack_archive(rustc_perf_zip_path)
+ move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir())
+ delete_file(rustc_perf_zip_path)
+
+ retry_action(download_rustc_perf, "Download rustc-perf")
+
+ with change_cwd(self.rustc_perf_dir()):
+ cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict(
+ RUSTC=str(self.rustc_stage_0()),
+ RUSTC_BOOTSTRAP="1"
+ ))
+
+ def rustc_profile_template_path(self) -> Path:
+ """
+ On Windows, we don't have enough space to use separate files for each rustc invocation.
+ Therefore, we use a single file for the generated profiles.
+ """
+ return self.rustc_profile_dir_root() / "default_%m.profraw"
+
+ def supports_bolt(self) -> bool:
+ return False
+
+
+class Timer:
+ def __init__(self):
+ # We want this dictionary to be ordered by insertion.
+ # We use `OrderedDict` for compatibility with older Python versions.
+ self.stages = OrderedDict()
+
+ @contextlib.contextmanager
+ def stage(self, name: str):
+ assert name not in self.stages
+
+ start = time.time()
+ exc = None
+ try:
+ LOGGER.info(f"Stage `{name}` starts")
+ yield
+ except BaseException as exception:
+ exc = exception
+ raise
+ finally:
+ end = time.time()
+ duration = end - start
+ self.stages[name] = duration
+ if exc is None:
+ LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)")
+ else:
+ LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)")
+
+ def print_stats(self):
+ total_duration = sum(self.stages.values())
+
+ # 57 is the width of the whole table
+ divider = "-" * 57
+
+ with StringIO() as output:
+ print(divider, file=output)
+ for (name, duration) in self.stages.items():
+ pct = (duration / total_duration) * 100
+ name_str = f"{name}:"
+ print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output)
+
+ total_duration_label = "Total duration:"
+ print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output)
+ print(divider, file=output, end="")
+ LOGGER.info(f"Timer results\n{output.getvalue()}")
+
+
+@contextlib.contextmanager
+def change_cwd(dir: Path):
+ """
+ Temporarily change working directory to `dir`.
+ """
+ cwd = os.getcwd()
+ LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`")
+ os.chdir(dir)
+ try:
+ yield
+ finally:
+ LOGGER.debug(f"Reverting working dir to `{cwd}`")
+ os.chdir(cwd)
+
+
+def move_path(src: Path, dst: Path):
+ LOGGER.info(f"Moving `{src}` to `{dst}`")
+ shutil.move(src, dst)
+
+
+def delete_file(path: Path):
+ LOGGER.info(f"Deleting file `{path}`")
+ os.unlink(path)
+
+
+def delete_directory(path: Path):
+ LOGGER.info(f"Deleting directory `{path}`")
+ shutil.rmtree(path)
+
+
+def unpack_archive(archive: Path):
+ LOGGER.info(f"Unpacking archive `{archive}`")
+ shutil.unpack_archive(archive)
+
+
+def download_file(src: str, target: Path):
+ LOGGER.info(f"Downloading `{src}` into `{target}`")
+ urllib.request.urlretrieve(src, str(target))
+
+
+def retry_action(action, name: str, max_fails: int = 5):
+ LOGGER.info(f"Attempting to perform action `{name}` with retry")
+ for iteration in range(max_fails):
+ LOGGER.info(f"Attempt {iteration + 1}/{max_fails}")
+ try:
+ action()
+ return
+ except:
+ LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}")
+
+ raise Exception(f"Action `{name}` has failed after {max_fails} attempts")
+
+
+def cmd(
+ args: List[Union[str, Path]],
+ env: Optional[Dict[str, str]] = None,
+ output_path: Optional[Path] = None
+):
+ args = [str(arg) for arg in args]
+
+ environment = os.environ.copy()
+
+ cmd_str = ""
+ if env is not None:
+ environment.update(env)
+ cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items())
+ cmd_str += " "
+ cmd_str += " ".join(args)
+ if output_path is not None:
+ cmd_str += f" > {output_path}"
+ LOGGER.info(f"Executing `{cmd_str}`")
+
+ if output_path is not None:
+ with open(output_path, "w") as f:
+ return subprocess.run(
+ args,
+ env=environment,
+ check=True,
+ stdout=f
+ )
+ return subprocess.run(args, env=environment, check=True)
+
+
+def run_compiler_benchmarks(
+ pipeline: Pipeline,
+ profiles: List[str],
+ scenarios: List[str],
+ crates: List[str],
+ env: Optional[Dict[str, str]] = None
+):
+ env = env if env is not None else {}
+
+ # Compile libcore, both in opt-level=0 and opt-level=3
+ with change_cwd(pipeline.build_root()):
+ cmd([
+ pipeline.rustc_stage_2(),
+ "--edition", "2021",
+ "--crate-type", "lib",
+ str(pipeline.checkout_path() / "library/core/src/lib.rs"),
+ "--out-dir", pipeline.opt_artifacts()
+ ], env=dict(RUSTC_BOOTSTRAP="1", **env))
+
+ cmd([
+ pipeline.rustc_stage_2(),
+ "--edition", "2021",
+ "--crate-type", "lib",
+ "-Copt-level=3",
+ str(pipeline.checkout_path() / "library/core/src/lib.rs"),
+ "--out-dir", pipeline.opt_artifacts()
+ ], env=dict(RUSTC_BOOTSTRAP="1", **env))
+
+ # Run rustc-perf benchmarks
+ # Benchmark using profile_local with eprintln, which essentially just means
+ # don't actually benchmark -- just make sure we run rustc a bunch of times.
+ with change_cwd(pipeline.rustc_perf_dir()):
+ cmd([
+ pipeline.cargo_stage_0(),
+ "run",
+ "-p", "collector", "--bin", "collector", "--",
+ "profile_local", "eprintln",
+ pipeline.rustc_stage_2(),
+ "--id", "Test",
+ "--cargo", pipeline.cargo_stage_0(),
+ "--profiles", ",".join(profiles),
+ "--scenarios", ",".join(scenarios),
+ "--include", ",".join(crates)
+ ], env=dict(
+ RUST_LOG="collector=debug",
+ RUSTC=str(pipeline.rustc_stage_0()),
+ RUSTC_BOOTSTRAP="1",
+ **env
+ ))
+
+
+# https://stackoverflow.com/a/31631711/1107768
+def format_bytes(size: int) -> str:
+ """Return the given bytes as a human friendly KiB, MiB or GiB string."""
+ KB = 1024
+ MB = KB ** 2 # 1,048,576
+ GB = KB ** 3 # 1,073,741,824
+ TB = KB ** 4 # 1,099,511,627,776
+
+ if size < KB:
+ return f"{size} B"
+ elif KB <= size < MB:
+ return f"{size / KB:.2f} KiB"
+ elif MB <= size < GB:
+ return f"{size / MB:.2f} MiB"
+ elif GB <= size < TB:
+ return f"{size / GB:.2f} GiB"
+ else:
+ return str(size)
+
+
+# https://stackoverflow.com/a/63307131/1107768
+def count_files(path: Path) -> int:
+ return sum(1 for p in path.rglob("*") if p.is_file())
+
+
+def count_files_with_prefix(path: Path) -> int:
+ return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file())
+
+
+# https://stackoverflow.com/a/55659577/1107768
+def get_path_size(path: Path) -> int:
+ if path.is_dir():
+ return sum(p.stat().st_size for p in path.rglob("*"))
+ return path.stat().st_size
+
+
+def get_path_prefix_size(path: Path) -> int:
+ """
+ Get size of all files beginning with the prefix `path`.
+ Alternative to shell `du -sh <path>*`.
+ """
+ return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*"))
+
+
+def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]:
+ for file in os.listdir(directory):
+ path = directory / file
+ if filter is None or filter(path):
+ yield path
+
+
+def build_rustc(
+ pipeline: Pipeline,
+ args: List[str],
+ env: Optional[Dict[str, str]] = None
+):
+ arguments = [
+ sys.executable,
+ pipeline.checkout_path() / "x.py",
+ "build",
+ "--target", PGO_HOST,
+ "--host", PGO_HOST,
+ "--stage", "2",
+ "library/std"
+ ] + args
+ cmd(arguments, env=env)
+
+
+def create_pipeline() -> Pipeline:
+ if sys.platform == "linux":
+ return LinuxPipeline()
+ elif sys.platform in ("cygwin", "win32"):
+ return WindowsPipeline()
+ else:
+ raise Exception(f"Optimized build is not supported for platform {sys.platform}")
+
+
+def gather_llvm_profiles(pipeline: Pipeline):
+ LOGGER.info("Running benchmarks with PGO instrumented LLVM")
+ run_compiler_benchmarks(
+ pipeline,
+ profiles=["Debug", "Opt"],
+ scenarios=["Full"],
+ crates=LLVM_PGO_CRATES
+ )
+
+ profile_path = pipeline.llvm_profile_merged_file()
+ LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}")
+ cmd([
+ pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata",
+ "merge",
+ "-o", profile_path,
+ pipeline.llvm_profile_dir_root()
+ ])
+
+ LOGGER.info("LLVM PGO statistics")
+ LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}")
+ LOGGER.info(
+ f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}")
+ LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}")
+
+ # We don't need the individual .profraw files now that they have been merged
+ # into a final .profdata
+ delete_directory(pipeline.llvm_profile_dir_root())
+
+
+def gather_rustc_profiles(pipeline: Pipeline):
+ LOGGER.info("Running benchmarks with PGO instrumented rustc")
+
+ # Here we're profiling the `rustc` frontend, so we also include `Check`.
+ # The benchmark set includes various stress tests that put the frontend under pressure.
+ run_compiler_benchmarks(
+ pipeline,
+ profiles=["Check", "Debug", "Opt"],
+ scenarios=["All"],
+ crates=RUSTC_PGO_CRATES,
+ env=dict(
+ LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path())
+ )
+ )
+
+ profile_path = pipeline.rustc_profile_merged_file()
+ LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}")
+ cmd([
+ pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata",
+ "merge",
+ "-o", profile_path,
+ pipeline.rustc_profile_dir_root()
+ ])
+
+ LOGGER.info("Rustc PGO statistics")
+ LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}")
+ LOGGER.info(
+ f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}")
+ LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}")
+
+ # We don't need the individual .profraw files now that they have been merged
+ # into a final .profdata
+ delete_directory(pipeline.rustc_profile_dir_root())
+
+
+def gather_llvm_bolt_profiles(pipeline: Pipeline):
+ LOGGER.info("Running benchmarks with BOLT instrumented LLVM")
+ run_compiler_benchmarks(
+ pipeline,
+ profiles=["Check", "Debug", "Opt"],
+ scenarios=["Full"],
+ crates=LLVM_BOLT_CRATES
+ )
+
+ merged_profile_path = pipeline.llvm_bolt_profile_merged_file()
+ profile_files_path = Path("/tmp/prof.fdata")
+ LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}")
+
+ profile_files = sorted(glob.glob(f"{profile_files_path}*"))
+ cmd([
+ "merge-fdata",
+ *profile_files,
+ ], output_path=merged_profile_path)
+
+ LOGGER.info("LLVM BOLT statistics")
+ LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}")
+ LOGGER.info(
+ f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}")
+ LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}")
+
+
+def clear_llvm_files(pipeline: Pipeline):
+ """
+ Rustbuild currently doesn't support rebuilding LLVM when PGO options
+ change (or any other llvm-related options); so just clear out the relevant
+ directories ourselves.
+ """
+ LOGGER.info("Clearing LLVM build files")
+ delete_directory(pipeline.build_artifacts() / "llvm")
+ delete_directory(pipeline.build_artifacts() / "lld")
+
+
+def print_binary_sizes(pipeline: Pipeline):
+ bin_dir = pipeline.build_artifacts() / "stage2" / "bin"
+ binaries = get_files(bin_dir)
+
+ lib_dir = pipeline.build_artifacts() / "stage2" / "lib"
+ libraries = get_files(lib_dir, lambda p: p.suffix == ".so")
+
+ paths = sorted(binaries) + sorted(libraries)
+ with StringIO() as output:
+ for path in paths:
+ path_str = f"{path.name}:"
+ print(f"{path_str:<30}{format_bytes(path.stat().st_size):>14}", file=output)
+ LOGGER.info(f"Rustc binary size\n{output.getvalue()}")
+
+
+def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]):
+ # Clear and prepare tmp directory
+ shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True)
+ os.makedirs(pipeline.opt_artifacts(), exist_ok=True)
+
+ pipeline.build_rustc_perf()
+
+ # Stage 1: Build rustc + PGO instrumented LLVM
+ with timer.stage("Build rustc (LLVM PGO)"):
+ build_rustc(pipeline, args=[
+ "--llvm-profile-generate"
+ ], env=dict(
+ LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
+ ))
+
+ with timer.stage("Gather profiles (LLVM PGO)"):
+ gather_llvm_profiles(pipeline)
+
+ clear_llvm_files(pipeline)
+ final_build_args += [
+ "--llvm-profile-use",
+ pipeline.llvm_profile_merged_file()
+ ]
+
+ # Stage 2: Build PGO instrumented rustc + LLVM
+ with timer.stage("Build rustc (rustc PGO)"):
+ build_rustc(pipeline, args=[
+ "--rust-profile-generate",
+ pipeline.rustc_profile_dir_root()
+ ])
+
+ with timer.stage("Gather profiles (rustc PGO)"):
+ gather_rustc_profiles(pipeline)
+
+ clear_llvm_files(pipeline)
+ final_build_args += [
+ "--rust-profile-use",
+ pipeline.rustc_profile_merged_file()
+ ]
+
+ # Stage 3: Build rustc + BOLT instrumented LLVM
+ if pipeline.supports_bolt():
+ with timer.stage("Build rustc (LLVM BOLT)"):
+ build_rustc(pipeline, args=[
+ "--llvm-profile-use",
+ pipeline.llvm_profile_merged_file(),
+ "--llvm-bolt-profile-generate",
+ ])
+ with timer.stage("Gather profiles (LLVM BOLT)"):
+ gather_llvm_bolt_profiles(pipeline)
+
+ clear_llvm_files(pipeline)
+ final_build_args += [
+ "--llvm-bolt-profile-use",
+ pipeline.llvm_bolt_profile_merged_file()
+ ]
+
+ # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM
+ with timer.stage("Final build"):
+ cmd(final_build_args)
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.DEBUG,
+ format="%(name)s %(levelname)-4s: %(message)s",
+ )
+
+ LOGGER.info(f"Running multi-stage build using Python {sys.version}")
+ LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}")
+
+ build_args = sys.argv[1:]
+
+ timer = Timer()
+ pipeline = create_pipeline()
+ try:
+ execute_build_pipeline(timer, pipeline, build_args)
+ except BaseException as e:
+ LOGGER.error("The multi-stage build has failed")
+ raise e
+ finally:
+ timer.print_stats()
+
+ print_binary_sizes(pipeline)
--- /dev/null
+# `tiny-const-eval-limit`
+
+--------------------
+
+The `-Ztiny-const-eval-limit` compiler flag sets a tiny, non-configurable limit for const eval.
+This flag should only be used by const eval tests in the rustc test suite.
echo "Running pre-push script $ROOT_DIR/x test tidy"
cd "$ROOT_DIR"
-./x test tidy
+CARGOFLAGS="--locked" ./x test tidy
})
})
.map(|item| format!("{}.{}", item.type_(), name));
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class,
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
clean::AssocTypeItem(tydef, _bounds) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
if trait_.is_some() {
// Anchors are only used on trait impls.
write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
} else {
format!(" data-aliases=\"{}\"", aliases.join(","))
};
- write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
+ write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
write!(w, "<h3 class=\"code-header\">");
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
- write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
+ write!(w, "<section id=\"{}\" class=\"method\">", id);
render_rightside(w, cx, m, t, RenderMode::Normal);
write!(w, "<h4 class=\"code-header\">");
render_assoc_item(
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => Ok(()),
}
}
cfg: Option<&str>,
) -> test::TestDesc {
let mut ignore = false;
- let ignore_message = None;
+ let mut ignore_message = None;
let mut should_fail = false;
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
if revision.is_some() && revision != cfg {
return;
}
+ macro_rules! reason {
+ ($e:expr) => {
+ ignore |= match $e {
+ true => {
+ ignore_message = Some(stringify!($e));
+ true
+ }
+ false => ignore,
+ }
+ };
+ }
ignore = match config.parse_cfg_name_directive(ln, "ignore") {
- ParsedNameDirective::Match => true,
+ ParsedNameDirective::Match => {
+ ignore_message = Some("cfg -> ignore => Match");
+ true
+ }
ParsedNameDirective::NoMatch => ignore,
};
+
if config.has_cfg_prefix(ln, "only") {
ignore = match config.parse_cfg_name_directive(ln, "only") {
ParsedNameDirective::Match => ignore,
- ParsedNameDirective::NoMatch => true,
+ ParsedNameDirective::NoMatch => {
+ ignore_message = Some("cfg -> only => NoMatch");
+ true
+ }
};
}
- ignore |= ignore_llvm(config, ln);
- ignore |=
- config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln);
- ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support");
- ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln);
- ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled");
- ignore |= !rustc_has_sanitizer_support
- && config.parse_name_directive(ln, "needs-sanitizer-support");
- ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
- ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
- ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi");
- ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
- ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
- ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
- ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
- ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
- ignore |= !has_shadow_call_stack
- && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
- ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind");
- ignore |= config.target == "wasm32-unknown-unknown"
- && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS);
- ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln);
- ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln);
- ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln);
- ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld");
+
+ reason!(ignore_llvm(config, ln));
+ reason!(
+ config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln)
+ );
+ reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support"));
+ reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln));
+ reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"));
+ reason!(
+ !rustc_has_sanitizer_support
+ && config.parse_name_directive(ln, "needs-sanitizer-support")
+ );
+ reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"));
+ reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"));
+ reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"));
+ reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"));
+ reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"));
+ reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"));
+ reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"));
+ reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"));
+ reason!(
+ !has_shadow_call_stack
+ && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack")
+ );
+ reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"));
+ reason!(
+ config.target == "wasm32-unknown-unknown"
+ && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
+ );
+ reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln));
+ reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln));
+ reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln));
+ reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"));
should_fail |= config.parse_name_directive(ln, "should-fail");
});
print("Refusing to decode " + str(type(content)) + " to str")
return json.loads(content_str)
-def validate_maintainers(repo, github_token):
- # type: (str, str) -> None
- '''Ensure all maintainers are assignable on a GitHub repo'''
- next_link_re = re.compile(r'<([^>]+)>; rel="next"')
-
- # Load the list of assignable people in the GitHub repo
- assignable = [] # type: typing.List[str]
- url = 'https://api.github.com/repos/' \
- + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str]
- while url is not None:
- response = urllib2.urlopen(urllib2.Request(url, headers={
- 'Authorization': 'token ' + github_token,
- # Properly load nested teams.
- 'Accept': 'application/vnd.github.hellcat-preview+json',
- }))
- assignable.extend(user['login'] for user in load_json_from_response(response))
- # Load the next page if available
- url = None
- link_header = response.headers.get('Link')
- if link_header:
- matches = next_link_re.match(link_header)
- if matches is not None:
- url = matches.group(1)
-
- errors = False
- for tool, maintainers in MAINTAINERS.items():
- for maintainer in maintainers:
- if maintainer not in assignable:
- errors = True
- print(
- "error: %s maintainer @%s is not assignable in the %s repo"
- % (tool, maintainer, repo),
- )
-
- if errors:
- print()
- print(" To be assignable, a person needs to be explicitly listed as a")
- print(" collaborator in the repository settings. The simple way to")
- print(" fix this is to ask someone with 'admin' privileges on the repo")
- print(" to add the person or whole team as a collaborator with 'read'")
- print(" privileges. Those privileges don't grant any extra permissions")
- print(" so it's safe to apply them.")
- print()
- print("The build will fail due to this.")
- exit(1)
-
def read_current_status(current_commit, path):
# type: (str, str) -> typing.Mapping[str, typing.Any]
try:
if __name__ != '__main__':
exit(0)
- repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO')
- if repo:
- github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN')
- if github_token:
- # FIXME: This is currently broken. Starting on 2021-09-15, GitHub
- # seems to have changed it so that to list the collaborators
- # requires admin permissions. I think this will probably just need
- # to be removed since we are probably not going to use an admin
- # token, and I don't see another way to do this.
- print('maintainer validation disabled')
- # validate_maintainers(repo, github_token)
- else:
- print('skipping toolstate maintainers validation since no GitHub token is present')
- # When validating maintainers don't run the full script.
- exit(0)
cur_commit = sys.argv[1]
cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
// compile-flags:-g
// min-gdb-version: 8.1
// ignore-lldb
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
// === CDB TESTS ==================================================================================
// compile-flags:-g
// min-gdb-version: 8.1
+// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows
// Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and
// `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
-// ignore-windows
// min-lldb-version: 310
// compile-flags:-g
_3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16
StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12
StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
- StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
- _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16
- StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
- _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
_5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20
- StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
- StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20
- StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
- _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
_4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24
- StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24
StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10
_9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28
StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2
- StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2
return; // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2
}
}
StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
_1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
- StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
-- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
-- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+- _4 = Eq(_1, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
- assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+ _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
}
bb1: {
-- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+ _5 = Eq(_1, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
- _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+ _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+ _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
}
bb2: {
-- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
- StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+ _2 = Rem(const 1_i32, _1); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
- StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
- _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
- StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
_5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
bb0: {
StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
- _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
- _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+ _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
- StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
_5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
bb0: {
StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
- StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
- _4 = _2; // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7
-- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
+- _3 = BitOr(_2, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
+ _3 = const true; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15
- StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15
StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
- StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
- _6 = _1; // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20
-- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
-+ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
- StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
+- _5 = BitAnd(_1, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
- _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
++ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29
+ _0 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29
StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29
let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
bb0: {
- StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
- _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4
-- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
+- _0 = Mul(_1, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
+ _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8
- StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8
return; // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2
}
}
StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
_4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
// mir::Constant
- // + span: $DIR/ref_deref.rs:6:6: 6:10
+ // + span: $DIR/ref_deref.rs:5:6: 5:10
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
- _2 = _4; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
+ _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
- nop; // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
}
}
+++ /dev/null
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
- let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
- let _3: i32; // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
-+ let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
- StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
-- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9
-- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+ _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
-+ // mir::Constant
-+ // + span: $DIR/ref_deref.rs:6:6: 6:10
-+ // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
-- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
- StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
- StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11
- _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2
- return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2
- }
- }
-
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref.main.PromoteTemps.diff
+// unit-test: ConstProp
// EMIT_MIR ref_deref.main.ConstProp.diff
fn main() {
StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
_4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
// mir::Constant
- // + span: $DIR/ref_deref_project.rs:6:6: 6:17
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17
// + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
_2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
- nop; // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
}
}
+++ /dev/null
-- // MIR for `main` before PromoteTemps
-+ // MIR for `main` after PromoteTemps
-
- fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
- let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
- let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
-+ let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
- StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
-- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14
-- _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+ _4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
-+ // mir::Constant
-+ // + span: $DIR/ref_deref_project.rs:6:6: 6:17
-+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
-+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
- _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
-- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
- StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
- StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18
- _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2
- return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2
- }
- }
-
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
-// EMIT_MIR ref_deref_project.main.PromoteTemps.diff
+// unit-test: ConstProp
// EMIT_MIR ref_deref_project.main.ConstProp.diff
fn main() {
StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
_1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
- StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
-- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
-- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-+ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+- _2 = consume(_1) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+ _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
// mir::Constant
// + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12
}
bb1: {
- StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
- StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
}
}
StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
// mir::Constant
- // + span: $DIR/slice_len.rs:6:6: 6:19
+ // + span: $DIR/slice_len.rs:7:6: 7:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+ _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
}
bb1: {
StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
- nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
}
}
StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
// mir::Constant
- // + span: $DIR/slice_len.rs:6:6: 6:19
+ // + span: $DIR/slice_len.rs:7:6: 7:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
+ _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
-+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33
}
bb1: {
StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34
- nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
+ _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2
return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2
}
}
-// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+InstCombine
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR slice_len.main.ConstProp.diff
fn bar() -> () {
let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10
let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
- let mut _2: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+ let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+ let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
scope 1 {
debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
- let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
scope 2 {
}
scope 3 {
- debug y => _3; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
}
}
StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
(_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
- StorageLive(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- _2 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
- (*_2) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
- StorageDead(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
- StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
- StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
- _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
- _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
- StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
- StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
+ StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+ StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+ (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
+ StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
+ _2 = const (); // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
+ StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6
+ StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+ StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+ _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
+ _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
+ StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
+ _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2
+ StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
return; // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2
}
_4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18
_3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25
StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25
+ _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2
StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
return; // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2
+// unit-test: ConstProp
#![feature(raw_ref_op)]
// EMIT_MIR const_prop_miscompile.foo.ConstProp.diff
--- /dev/null
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+
+ fn f() -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/borrowed_local.rs:+0:11: +0:15
+ let mut _1: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _2: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _4: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ _1 = const 5_u8; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _2 = &_1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _3 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _4 = &_3; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _0 = cmp_ref(_2, _4) -> bb1; // scope 0 at $DIR/borrowed_local.rs:+8:13: +8:45
+ // mir::Constant
+ // + span: $DIR/borrowed_local.rs:23:29: 23:36
+ // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+- _0 = opaque::<u8>(_3) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
++ _0 = opaque::<u8>(_1) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38
+ // mir::Constant
+ // + span: $DIR/borrowed_local.rs:27:28: 27:34
+ // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/borrowed_local.rs:+15:13: +15:21
+ }
+ }
+
--- /dev/null
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+fn cmp_ref(a: &u8, b: &u8) -> bool {
+ std::ptr::eq(a as *const u8, b as *const u8)
+}
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f() -> bool {
+ mir!(
+ {
+ let a = 5_u8;
+ let r1 = &a;
+ let b = a;
+ // We cannot propagate the place `a`.
+ let r2 = &b;
+ Call(RET, next, cmp_ref(r1, r2))
+ }
+ next = {
+ // But we can propagate the value `a`.
+ Call(RET, ret, opaque(b))
+ }
+ ret = {
+ Return()
+ }
+ )
+}
+
+fn main() {
+ assert!(!f());
+}
+
+// EMIT_MIR borrowed_local.f.CopyProp.diff
--- /dev/null
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+
+ fn foo() -> i32 {
+ let mut _0: i32; // return place in scope 0 at $DIR/branch.rs:+0:13: +0:16
+ let _1: i32; // in scope 0 at $DIR/branch.rs:+1:9: +1:10
+ let mut _3: bool; // in scope 0 at $DIR/branch.rs:+3:16: +3:22
+ let _4: i32; // in scope 0 at $DIR/branch.rs:+6:9: +6:14
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/branch.rs:+1:9: +1:10
+ let _2: i32; // in scope 1 at $DIR/branch.rs:+3:9: +3:10
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/branch.rs:+3:9: +3:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/branch.rs:+1:9: +1:10
+ _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:+1:13: +1:18
+ // mir::Constant
+ // + span: $DIR/branch.rs:13:13: 13:16
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageLive(_2); // scope 1 at $DIR/branch.rs:+3:9: +3:10
+ StorageLive(_3); // scope 1 at $DIR/branch.rs:+3:16: +3:22
+ _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:+3:16: +3:22
+ // mir::Constant
+ // + span: $DIR/branch.rs:15:16: 15:20
+ // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22
+ }
+
+ bb3: {
+ _2 = _1; // scope 1 at $DIR/branch.rs:+4:9: +4:10
+ goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6
+ }
+
+ bb4: {
+ StorageLive(_4); // scope 1 at $DIR/branch.rs:+6:9: +6:14
+ _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:+6:9: +6:14
+ // mir::Constant
+ // + span: $DIR/branch.rs:18:9: 18:12
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+ }
+
+ bb5: {
+ StorageDead(_4); // scope 1 at $DIR/branch.rs:+6:14: +6:15
+ _2 = _1; // scope 1 at $DIR/branch.rs:+7:9: +7:10
+ goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6
+ }
+
+ bb6: {
+ StorageDead(_3); // scope 1 at $DIR/branch.rs:+8:5: +8:6
+ _0 = _2; // scope 2 at $DIR/branch.rs:+10:5: +10:6
+ StorageDead(_2); // scope 1 at $DIR/branch.rs:+11:1: +11:2
+ StorageDead(_1); // scope 0 at $DIR/branch.rs:+11:1: +11:2
+ return; // scope 0 at $DIR/branch.rs:+11:2: +11:2
+ }
+ }
+
--- /dev/null
+//! Tests that we bail out when there are multiple assignments to the same local.
+// unit-test: CopyProp
+fn val() -> i32 {
+ 1
+}
+
+fn cond() -> bool {
+ true
+}
+
+// EMIT_MIR branch.foo.CopyProp.diff
+fn foo() -> i32 {
+ let x = val();
+
+ let y = if cond() {
+ x
+ } else {
+ val();
+ x
+ };
+
+ y
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+- // MIR for `arg_src` before CopyProp
++ // MIR for `arg_src` after CopyProp
+
+ fn arg_src(_1: i32) -> i32 {
+ debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17
+ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30
+ let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+ scope 1 {
+ debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10
+ _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+ _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12
+ _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+ StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+ }
+ }
+
--- /dev/null
+- // MIR for `bar` before CopyProp
++ // MIR for `bar` after CopyProp
+
+ fn bar(_1: u8) -> () {
+ debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+ let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+ let _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+ StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+ _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
+ _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13
+ // mir::Constant
+ // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
+ // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13
+ StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14
+ _1 = const 5_u8; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+ _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+ return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+ }
+ }
+
--- /dev/null
+- // MIR for `baz` before CopyProp
++ // MIR for `baz` after CopyProp
+
+ fn baz(_1: i32) -> i32 {
+ debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:23: +0:26
+ let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+ _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+ _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10
+ StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10
+ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+3:5: +3:6
+ return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2
+ }
+ }
+
--- /dev/null
+- // MIR for `foo` before CopyProp
++ // MIR for `foo` after CopyProp
+
+ fn foo(_1: u8) -> () {
+ debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13
+ let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19
+ let mut _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+ StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+ _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16
+ _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
+ // mir::Constant
+ // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
+ // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+ _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17
+ StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17
+ _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2
+ return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2
+ }
+ }
+
--- /dev/null
+// Check that CopyProp does not propagate an assignment to a function argument
+// (doing so can break usages of the original argument value)
+// unit-test: CopyProp
+fn dummy(x: u8) -> u8 {
+ x
+}
+
+// EMIT_MIR copy_propagation_arg.foo.CopyProp.diff
+fn foo(mut x: u8) {
+ // calling `dummy` to make a use of `x` that copyprop cannot eliminate
+ x = dummy(x); // this will assign a local to `x`
+}
+
+// EMIT_MIR copy_propagation_arg.bar.CopyProp.diff
+fn bar(mut x: u8) {
+ dummy(x);
+ x = 5;
+}
+
+// EMIT_MIR copy_propagation_arg.baz.CopyProp.diff
+fn baz(mut x: i32) -> i32 {
+ // self-assignment to a function argument should be eliminated
+ x = x;
+ x
+}
+
+// EMIT_MIR copy_propagation_arg.arg_src.CopyProp.diff
+fn arg_src(mut x: i32) -> i32 {
+ let y = x;
+ x = 123; // Don't propagate this assignment to `y`
+ y
+}
+
+fn main() {
+ // Make sure the function actually gets instantiated.
+ foo(0);
+ bar(0);
+ baz(0);
+ arg_src(0);
+}
--- /dev/null
+- // MIR for `main` before CopyProp
++ // MIR for `main` after CopyProp
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11
+ let mut _1: i32; // in scope 0 at $DIR/cycle.rs:+1:9: +1:14
+ let mut _4: i32; // in scope 0 at $DIR/cycle.rs:+4:9: +4:10
+ let _5: (); // in scope 0 at $DIR/cycle.rs:+6:5: +6:12
+ let mut _6: i32; // in scope 0 at $DIR/cycle.rs:+6:10: +6:11
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/cycle.rs:+1:9: +1:14
+ let _2: i32; // in scope 1 at $DIR/cycle.rs:+2:9: +2:10
+ scope 2 {
+ debug y => _2; // in scope 2 at $DIR/cycle.rs:+2:9: +2:10
+ let _3: i32; // in scope 2 at $DIR/cycle.rs:+3:9: +3:10
+ scope 3 {
+- debug z => _3; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
++ debug z => _2; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:14
+ _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:+1:17: +1:22
+ // mir::Constant
+ // + span: $DIR/cycle.rs:9:17: 9:20
+ // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageLive(_2); // scope 1 at $DIR/cycle.rs:+2:9: +2:10
+ _2 = _1; // scope 1 at $DIR/cycle.rs:+2:13: +2:14
+- StorageLive(_3); // scope 2 at $DIR/cycle.rs:+3:9: +3:10
+- _3 = _2; // scope 2 at $DIR/cycle.rs:+3:13: +3:14
+- StorageLive(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+- _4 = _3; // scope 3 at $DIR/cycle.rs:+4:9: +4:10
+- _1 = move _4; // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+- StorageDead(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10
++ _1 = _2; // scope 3 at $DIR/cycle.rs:+4:5: +4:10
+ StorageLive(_5); // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+ StorageLive(_6); // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+ _6 = _1; // scope 3 at $DIR/cycle.rs:+6:10: +6:11
+ _5 = std::mem::drop::<i32>(move _6) -> bb2; // scope 3 at $DIR/cycle.rs:+6:5: +6:12
+ // mir::Constant
+ // + span: $DIR/cycle.rs:14:5: 14:9
+ // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_6); // scope 3 at $DIR/cycle.rs:+6:11: +6:12
+ StorageDead(_5); // scope 3 at $DIR/cycle.rs:+6:12: +6:13
+ _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +7:2
+- StorageDead(_3); // scope 2 at $DIR/cycle.rs:+7:1: +7:2
+- StorageDead(_2); // scope 1 at $DIR/cycle.rs:+7:1: +7:2
+ StorageDead(_1); // scope 0 at $DIR/cycle.rs:+7:1: +7:2
+ return; // scope 0 at $DIR/cycle.rs:+7:2: +7:2
+ }
+ }
+
--- /dev/null
+//! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code.
+// unit-test: CopyProp
+fn val() -> i32 {
+ 1
+}
+
+// EMIT_MIR cycle.main.CopyProp.diff
+fn main() {
+ let mut x = val();
+ let y = x;
+ let z = y;
+ x = z;
+
+ drop(x);
+}
--- /dev/null
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+ debug a => _1; // in scope 0 at $DIR/dead_stores_79191.rs:+0:6: +0:11
+ let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_79191.rs:+0:23: +0:28
+ let _2: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+ let mut _3: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+3:9: +3:10
+ let mut _4: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+ scope 1 {
+ debug b => _2; // in scope 1 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10
+ _2 = _1; // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14
+ _1 = const 5_usize; // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10
+ _1 = _2; // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10
+ StorageLive(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+ _4 = _1; // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
+ _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_79191.rs:+4:5: +4:10
+ // mir::Constant
+ // + span: $DIR/dead_stores_79191.rs:12:5: 12:7
+ // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:9: +4:10
+ return; // scope 0 at $DIR/dead_stores_79191.rs:+5:2: +5:2
+ }
+}
--- /dev/null
+// unit-test: CopyProp
+
+fn id<T>(x: T) -> T {
+ x
+}
+
+// EMIT_MIR dead_stores_79191.f.CopyProp.after.mir
+fn f(mut a: usize) -> usize {
+ let b = a;
+ a = 5;
+ a = b;
+ id(a)
+}
+
+fn main() {
+ f(0);
+}
--- /dev/null
+// MIR for `f` after CopyProp
+
+fn f(_1: usize) -> usize {
+ debug a => _1; // in scope 0 at $DIR/dead_stores_better.rs:+0:10: +0:15
+ let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_better.rs:+0:27: +0:32
+ let _2: usize; // in scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+ let mut _3: usize; // in scope 0 at $DIR/dead_stores_better.rs:+3:9: +3:10
+ let mut _4: usize; // in scope 0 at $DIR/dead_stores_better.rs:+4:8: +4:9
+ scope 1 {
+ debug b => _2; // in scope 1 at $DIR/dead_stores_better.rs:+1:9: +1:10
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
+ _2 = _1; // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
+ _1 = const 5_usize; // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
+ _1 = _2; // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
+ StorageLive(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+ _4 = _1; // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
+ _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_better.rs:+4:5: +4:10
+ // mir::Constant
+ // + span: $DIR/dead_stores_better.rs:16:5: 16:7
+ // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:9: +4:10
+ return; // scope 0 at $DIR/dead_stores_better.rs:+5:2: +5:2
+ }
+}
--- /dev/null
+// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates
+// that that pass enables this one to do more optimizations.
+
+// unit-test: CopyProp
+// compile-flags: -Zmir-enable-passes=+DeadStoreElimination
+
+fn id<T>(x: T) -> T {
+ x
+}
+
+// EMIT_MIR dead_stores_better.f.CopyProp.after.mir
+pub fn f(mut a: usize) -> usize {
+ let b = a;
+ a = 5;
+ a = b;
+ id(a)
+}
+
+fn main() {
+ f(0);
+}
--- /dev/null
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+
+ fn f(_1: T) -> () {
+ debug a => _1; // in scope 0 at $DIR/move_arg.rs:+0:19: +0:20
+ let mut _0: (); // return place in scope 0 at $DIR/move_arg.rs:+0:25: +0:25
+ let _2: T; // in scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+ let _3: (); // in scope 0 at $DIR/move_arg.rs:+2:5: +2:12
+ let mut _4: T; // in scope 0 at $DIR/move_arg.rs:+2:7: +2:8
+ let mut _5: T; // in scope 0 at $DIR/move_arg.rs:+2:10: +2:11
+ scope 1 {
+- debug b => _2; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
++ debug b => _1; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10
+ }
+
+ bb0: {
+- StorageLive(_2); // scope 0 at $DIR/move_arg.rs:+1:9: +1:10
+- _2 = _1; // scope 0 at $DIR/move_arg.rs:+1:13: +1:14
+ StorageLive(_3); // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+- StorageLive(_4); // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+- _4 = _1; // scope 1 at $DIR/move_arg.rs:+2:7: +2:8
+- StorageLive(_5); // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+- _5 = _2; // scope 1 at $DIR/move_arg.rs:+2:10: +2:11
+- _3 = g::<T>(move _4, move _5) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
++ _3 = g::<T>(_1, _1) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12
+ // mir::Constant
+ // + span: $DIR/move_arg.rs:7:5: 7:6
+ // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+- StorageDead(_5); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+- StorageDead(_4); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12
+ StorageDead(_3); // scope 1 at $DIR/move_arg.rs:+2:12: +2:13
+ _0 = const (); // scope 0 at $DIR/move_arg.rs:+0:25: +3:2
+- StorageDead(_2); // scope 0 at $DIR/move_arg.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/move_arg.rs:+3:2: +3:2
+ }
+ }
+
--- /dev/null
+// Test that we do not move multiple times from the same local.
+// unit-test: CopyProp
+
+// EMIT_MIR move_arg.f.CopyProp.diff
+pub fn f<T: Copy>(a: T) {
+ let b = a;
+ g(a, b);
+}
+
+#[inline(never)]
+pub fn g<T: Copy>(_: T, _: T) {}
+
+fn main() {
+ f(5)
+}
--- /dev/null
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+
+ fn f(_1: bool) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/mutate_through_pointer.rs:+0:18: +0:22
+ let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _3: *const bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _4: *mut bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _3 = &raw const _2; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _4 = &raw mut (*_3); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ (*_4) = const false; // scope 0 at $DIR/mutate_through_pointer.rs:+5:9: +5:20
+ _0 = _1; // scope 0 at $DIR/mutate_through_pointer.rs:+6:9: +6:16
+ return; // scope 0 at $DIR/mutate_through_pointer.rs:+7:9: +7:17
+ }
+ }
+
--- /dev/null
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+ mir!({
+ let a = c;
+ let p = core::ptr::addr_of!(a);
+ let p2 = core::ptr::addr_of_mut!(*p);
+ *p2 = false;
+ RET = c;
+ Return()
+ })
+}
+
+fn main() {
+ assert_eq!(true, f(true));
+}
+
+// EMIT_MIR mutate_through_pointer.f.CopyProp.diff
--- /dev/null
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+
+ fn f(_1: bool) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/non_dominate.rs:+0:18: +0:22
+ let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _3: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+4:11: +4:20
+ }
+
+ bb1: {
+ _3 = _1; // scope 0 at $DIR/non_dominate.rs:+5:17: +5:22
+ switchInt(_3) -> [0: bb3, otherwise: bb2]; // scope 0 at $DIR/non_dominate.rs:+5:24: +5:58
+ }
+
+ bb2: {
+ _2 = _3; // scope 0 at $DIR/non_dominate.rs:+8:17: +8:22
+ _1 = const false; // scope 0 at $DIR/non_dominate.rs:+8:24: +8:33
+ goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+8:35: +8:44
+ }
+
+ bb3: {
+ _0 = _2; // scope 0 at $DIR/non_dominate.rs:+9:17: +9:24
+ return; // scope 0 at $DIR/non_dominate.rs:+9:26: +9:34
+ }
+ }
+
--- /dev/null
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(c: bool) -> bool {
+ mir!(
+ let a: bool;
+ let b: bool;
+ { Goto(bb1) }
+ bb1 = { b = c; match b { false => bb3, _ => bb2 }}
+ // This assignment to `a` does not dominate the use in `bb3`.
+ // It should not be replaced by `b`.
+ bb2 = { a = b; c = false; Goto(bb1) }
+ bb3 = { RET = a; Return() }
+ )
+}
+
+fn main() {
+ assert_eq!(true, f(true));
+}
+
+// EMIT_MIR non_dominate.f.CopyProp.diff
_1 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
StorageLive(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
_2 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- StorageLive(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- _3 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageLive(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- _4 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
_5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
}
bb1: {
- StorageDead(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageDead(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
- StorageDead(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
- StorageDead(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
return; // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2
}
}
}
bb1: {
- _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ _0 = Div(const 256_i32, _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
}
}
let mut _0: i32; // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36
bb0: {
- _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+ _0 = Div(_1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
}
}
_10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26
StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
_11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46
- StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
- _12 = _2; // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51
StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
_13 = _6; // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57
StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
- StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
- _16 = _10; // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68
- _15 = move _16 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
- StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75
+ _15 = _10 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75
_14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79
StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79
- StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
- _17 = _3; // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86
- _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
+ _0 = float_to_exponential_common_exact::<T>(move _11, _2, move _13, move _14, _3) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87
// mir::Constant
// + span: $DIR/funky_arms.rs:26:9: 26:42
// + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
}
bb7: {
- StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
- StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87
- StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6
goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
}
bb8: {
StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
_18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49
- StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
- _19 = _2; // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54
StorageLive(_20); // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
_20 = _6; // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
- StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
- _21 = _3; // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67
- _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
+ _0 = float_to_exponential_common_shortest::<T>(move _18, _2, move _20, _3) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68
// mir::Constant
// + span: $DIR/funky_arms.rs:28:9: 28:45
// + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
}
bb9: {
- StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
- StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68
goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6
}
_4 = &(*_2); // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25
+ StorageLive(_5); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+ _5 = move _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
++ _5 = _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
// mir::Constant
- // + span: $DIR/dyn_trait.rs:34:5: 34:22
- // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
_2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
StorageDead(_3); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16
-+ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
++ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
// mir::Constant
- // + span: $DIR/dyn_trait.rs:27:5: 27:13
- // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
_3 = const 1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
StorageLive(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
_4 = const -1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
- _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
+ _0 = Eq(_3, _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
StorageDead(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
StorageDead(_3); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
StorageDead(_2); // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13
+
+ bb3: {
+ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
-+ switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++ switchInt(_7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
+ }
+
+ bb4: {
+ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
+ StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
+ Deinit(_1); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
-+ ((_1 as Complete).0: bool) = move _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ ((_1 as Complete).0: bool) = _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
+ discriminant(_1) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
+ _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
+ discriminant((*_12)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
_3 = &(*_1); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
_2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
StorageDead(_3); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
- _0 = <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
+ _0 = <dyn X as X>::y(_2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
// mir::Constant
// + span: $DIR/inline_trait_method_2.rs:10:7: 10:8
// + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
let mut _10: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
let mut _11: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17
- debug x => _5; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
+ debug x => _1; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
let mut _12: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
let mut _13: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
let mut _14: (u32, bool); // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
- StorageLive(_5); // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
- _5 = _1; // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
StorageLive(_12); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
StorageLive(_13); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
- _14 = CheckedShr(_5, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+ _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
}
bb1: {
_8 = move (_10.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
- StorageDead(_9); // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45
_7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
_11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
bb2: {
_6 = move (_11.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
StorageDead(_7); // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
- StorageLive(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- _15 = _4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- StorageLive(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- _16 = _6; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- _3 = rotate_right::<u32>(move _15, move _16) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+ _3 = rotate_right::<u32>(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
// + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::<u32>}, val: Value(<ZST>) }
StorageDead(_13); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
_4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
StorageDead(_12); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
- StorageDead(_5); // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17
StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
- StorageLive(_9); // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
- _9 = _1; // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
- _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
}
bb4: {
- StorageDead(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- StorageDead(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- StorageDead(_6); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
- StorageDead(_4); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
_2 = move _3 as i32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
StorageDead(_3); // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65
_0 = move _2 as i64 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72
bb0: {
StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
- StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
- _6 = _1; // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
- StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
- _7 = _1; // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
- StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
- _8 = _1; // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
- _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
- StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
- StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
- StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
+ _5 = [_1, _1, _1]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29
_4 = &_5; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
- _3 = _4; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
- _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
- StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
- StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
+ _2 = _4 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
_9 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
_10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
- _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
bb0: {
StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
}
bb1: {
- _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
}
bb2: {
debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- let mut _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- let mut _10: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ let _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ let mut _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ let mut _9: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
bb0: {
StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
- StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+ _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
}
bb1: {
- _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
}
bb2: {
}
bb3: {
- StorageLive(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- _8 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- _9 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- _10 = Lt(const 0_usize, _9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ StorageLive(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ _7 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+ _8 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ _9 = Lt(const 0_usize, _8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
}
bb4: {
- (*_2)[_8] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
- StorageDead(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
+ (*_2)[_7] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
+ StorageDead(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
_0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
}
bb3: {
_5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
- _4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+ _4 = Add(_5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31
StorageLive(_2); // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18
_2 = const false; // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26
-- _1 = _2; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
-+ _1 = const false; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
- StorageDead(_2); // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31
-- switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
+- switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
+ switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
}
}
bb3: {
- StorageDead(_1); // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2
return; // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2
}
}
--- /dev/null
+fn main() {
+ let input = vec![];
+ let _variant_a_result = variant_a(&input);
+ let _variant_b_result = variant_b(&input);
+}
+
+pub fn variant_a(input: &[(usize, usize, usize, usize)]) -> usize {
+ input.iter().filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+pub fn variant_b(input: &[(usize, usize, usize, usize)]) -> usize {
+ input.iter().filter(|&&(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count()
+}
+
+// EMIT_MIR slice_filter.variant_a-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_a-{closure#0}.DestinationPropagation.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.CopyProp.diff
+// EMIT_MIR slice_filter.variant_b-{closure#0}.DestinationPropagation.diff
--- /dev/null
+- // MIR for `variant_a::{closure#0}` before CopyProp
++ // MIR for `variant_a::{closure#0}` after CopyProp
+
+ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+ let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+ let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+ let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+ let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+ let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+ let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+ let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+ let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+ let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+ let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+ let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+ let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+ let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+ let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+ let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+ let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+ let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+ let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+ let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ scope 1 {
+ debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+ debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+ debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+ debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+ scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+ debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _31: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _32: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug self => _31; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug other => _32; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _33: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _34: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+ debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _35: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _36: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _37: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _38: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug self => _35; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug other => _36; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug self => _37; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug other => _38; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _39: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _40: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+ debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _41: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _42: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _43: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _44: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug self => _41; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug other => _42; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug self => _43; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug other => _44; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _45: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _46: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+ debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _47: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _48: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _49: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _50: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug self => _47; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- debug other => _48; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug self => _49; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ debug other => _50; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _51: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _52: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+ StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+ _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+ StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+- StorageLive(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _31 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _29 = _31; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageLive(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _32 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _30 = _32; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _33 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _33 = (*_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _34 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _34 = (*_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _8 = Le(move _33, move _34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ }
+
+ bb1: {
+ _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+
+ bb2: {
+ StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+ StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+ _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+ StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+- StorageLive(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _37 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _35 = _37; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageLive(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _38 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _36 = _38; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _39 = (*_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _39 = (*_37); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _40 = (*_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _40 = (*_38); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _17 = Le(move _39, move _40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb3: {
+ StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+ return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+ }
+
+ bb4: {
+ _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ }
+
+ bb5: {
+ StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+ StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+ _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+ StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+- StorageLive(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _43 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _41 = _43; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageLive(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _44 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _42 = _44; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _45 = (*_41); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _45 = (*_43); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _46 = (*_42); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _46 = (*_44); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _12 = Le(move _45, move _46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+
+ bb6: {
+ _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb7: {
+ StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+ StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+ _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+ StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageLive(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _49 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _47 = _49; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageLive(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _50 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _48 = _50; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _51 = (*_47); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _51 = (*_49); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _52 = (*_48); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _52 = (*_50); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _21 = Le(move _51, move _52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- StorageDead(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb8: {
+ StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+ }
+
--- /dev/null
+- // MIR for `variant_a::{closure#0}` before DestinationPropagation
++ // MIR for `variant_a::{closure#0}` after DestinationPropagation
+
+ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40
+ let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56
+ let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46
+ let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41
+ let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+ let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46
+ let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56
+ let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51
+ let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+ let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56
+ let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76
+ let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66
+ let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61
+ let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+ let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66
+ let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76
+ let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71
+ let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+ let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76
+ let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38
+ scope 1 {
+ debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28
+ debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31
+ debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34
+ debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37
+ scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46
+ debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _31: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _32: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66
+ debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _33: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _34: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug self => _33; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _34; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _35: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _36: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56
+ debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _37: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _38: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug self => _37; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _38; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _39: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _40: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76
+ debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _41: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _42: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug self => _41; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ debug other => _42; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _43: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ let mut _44: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28
+ StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31
+ StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34
+ StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+ _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37
+- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46
+ StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+ _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41
+ StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ _29 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _30 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _31 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _32 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _8 = Le(move _31, move _32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46
+ switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ }
+
+ bb1: {
+ _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+
+ bb2: {
+- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66
+ StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+ _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61
+ StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ _33 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _34 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _35 = (*_33); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _36 = (*_34); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _17 = Le(move _35, move _36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66
+ switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb3: {
+- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76
+ }
+
+ bb4: {
+- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+ }
+
+ bb5: {
+- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56
+ StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+ _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51
+ StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ _37 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _38 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _39 = (*_37); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _40 = (*_38); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _12 = Le(move _39, move _40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+- _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
+- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56
+- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++ switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+
+ bb6: {
+- _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb7: {
+- StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76
+ StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+ _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71
+ StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ _41 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _42 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _43 = (*_41); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageLive(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ _44 = (*_42); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+- _21 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
++ _0 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL
+ StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+- _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76
+ }
+
+ bb8: {
+- StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+ StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76
+- _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76
+ }
+ }
+
--- /dev/null
+- // MIR for `variant_b::{closure#0}` before CopyProp
++ // MIR for `variant_b::{closure#0}` after CopyProp
+
+ fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+ let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+ let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+ let mut _9: usize; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:43
+ let mut _10: usize; // in scope 0 at $DIR/slice_filter.rs:+0:47: +0:48
+ let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+ let mut _12: usize; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:53
+ let mut _13: usize; // in scope 0 at $DIR/slice_filter.rs:+0:57: +0:58
+ let mut _14: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+ let mut _15: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+ let mut _16: usize; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:63
+ let mut _17: usize; // in scope 0 at $DIR/slice_filter.rs:+0:67: +0:68
+ let mut _18: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+ let mut _19: usize; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:73
+ let mut _20: usize; // in scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+ let mut _21: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _22: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _23: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _24: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ scope 1 {
+ debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+ debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+ debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+ debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+ }
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ _21 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ _3 = ((*_21).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ _22 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ _4 = ((*_22).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ _23 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ _5 = ((*_23).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ _24 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ _6 = ((*_24).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+- _9 = _3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43
+- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+- _10 = _5; // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+- _8 = Le(move _9, move _10); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
+- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48
++ _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+ switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ }
+
+ bb1: {
+ _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+
+ bb2: {
+ StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+- _16 = _5; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63
+- StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+- _17 = _3; // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+- _15 = Le(move _16, move _17); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+- StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
+- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68
++ _15 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+ switchInt(move _15) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb3: {
+ StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+ StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78
+ return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+ }
+
+ bb4: {
+ _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ }
+
+ bb5: {
+ StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+- _12 = _6; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53
+- StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+- _13 = _4; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+- _11 = Le(move _12, move _13); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+- StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++ _11 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+ _7 = move _11; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+
+ bb6: {
+ _14 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb7: {
+ StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+- StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+- _19 = _4; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73
+- StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- _20 = _6; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- _18 = Le(move _19, move _20); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+- StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++ _18 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+ _14 = move _18; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb8: {
+ StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+ StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+ _0 = move _14; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+ }
+
--- /dev/null
+- // MIR for `variant_b::{closure#0}` before DestinationPropagation
++ // MIR for `variant_b::{closure#0}` after DestinationPropagation
+
+ fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42
+ let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58
+ let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48
+ let mut _9: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58
+ let mut _10: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78
+ let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68
+ let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78
+ let mut _13: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _14: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _15: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ let mut _16: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40
+ scope 1 {
+ debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30
+ debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33
+ debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36
+ debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39
+ }
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ _13 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ _3 = ((*_13).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30
+ StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ _14 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ _4 = ((*_14).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33
+ StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ _15 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ _5 = ((*_15).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36
+ StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ _16 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+ _6 = ((*_16).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39
+- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+ _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48
+ switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ }
+
+ bb1: {
+ _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+
+ bb2: {
+- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+ _11 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68
+ switchInt(move _11) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb3: {
+- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+ return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78
+ }
+
+ bb4: {
+- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+ }
+
+ bb5: {
+- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+ _9 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58
+- _7 = move _9; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
+- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+ StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58
+- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++ switchInt(move _9) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+
+ bb6: {
+- _10 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb7: {
+- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+- _12 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
+- _10 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++ _0 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78
+ }
+
+ bb8: {
+- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+ StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78
+- _0 = move _10; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78
+ }
+ }
+
let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
let mut _3: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22
- let mut _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49
- let mut _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+ let _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+ let _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
let mut _6: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37
let _7: T; // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
- let mut _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+ let _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
scope 1 {
debug v => _4; // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21
}
}
bb1: {
+ StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
_5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
Deinit(_2); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
((_2 as Break).0: E) = move _5; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
}
bb2: {
+ StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
_4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
Deinit(_2); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
}
bb3: {
+ StorageLive(_8); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
_8 = move ((_2 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
Deinit(_0); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
((_0 as Err).0: E) = move _8; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
}
bb5: {
+ StorageLive(_7); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
_7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
((_0 as Ok).0: T) = move _7; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
let mut _2: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18
let _3: T; // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
- let mut _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+ let _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
scope 1 {
debug v => _3; // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17
}
}
bb1: {
+ StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
_4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
((_0 as Err).0: E) = move _4; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
}
bb3: {
+ StorageLive(_3); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
_3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
((_0 as Ok).0: T) = move _3; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
debug c => _1; // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16
let mut _0: (); // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24
let mut _2: bool; // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22
- let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21
- let mut _4: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
- let mut _5: bool; // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22
+ let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
bb0: {
goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
bb1: {
StorageLive(_2); // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
- StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
- _3 = _1; // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
- _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+ _2 = get_bool(_1) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
// mir::Constant
// + span: $DIR/while_storage.rs:10:11: 10:19
// + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+1:21: +1:22
switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
}
bb3: {
- StorageLive(_4); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
- StorageLive(_5); // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
- _5 = _1; // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
- _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+ StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+ _3 = get_bool(_1) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
// mir::Constant
// + span: $DIR/while_storage.rs:11:12: 11:20
// + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
}
bb4: {
- StorageDead(_5); // scope 0 at $DIR/while_storage.rs:+2:22: +2:23
- switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+ switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
}
bb5: {
- StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+ StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
goto -> bb7; // scope 0 at no-location
}
bb6: {
- StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+ StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
}
((::alloc::fmt::format as
for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1
as
- fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
+ fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
as &str)] as [&str; 1]) as &[&str; 1]),
- (&([] as [ArgumentV1<'_>; 0]) as &[ArgumentV1<'_>; 0])) as
- Arguments<'_>)) as String);
+ (&([] as [core::fmt::ArgumentV1<'_>; 0]) as
+ &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as
+ String);
(res as String)
} as String);
} as ())
# We're using the llvm-nm instead of the system nm to ensure it is compatible
# with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
all: $(call NATIVE_STATICLIB,native-staticlib)
# Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
include ../../run-make-fulldeps/tools.mk
+# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility
+# with the LLVM bitcode generated by rustc but on Windows piping/IO redirection under MSYS2 is wonky with llvm-objdump.
+OBJDUMP = objdump
+
all:
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
# Make sure we don't find an import to the functions we expect to be inlined.
- "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
- "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
+ $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
+ $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
# Make sure we do find an import to the functions we expect to be imported.
- "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
+ $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
ifdef IS_MSVC
# We're using the llvm-nm instead of the system nm to ensure it is compatible
# with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
all:
# Build strange-named dep.
# We're using the llvm-nm instead of the system nm to ensure it is compatible
# with the LLVM bitcode generated by rustc.
+# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
+ifndef IS_WINDOWS
NM = "$(LLVM_BIN_DIR)"/llvm-nm
+else
+NM = nm
+endif
all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3)
$(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
show-text: true
// Check the impl headers.
-assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
+assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL)
// Check the impl items.
-assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
-assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
+assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL)
+assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL)
// Check that we can click on source link
store-document-property: (url, "URL")
-click: ".impl-items .has-srclink .srclink"
+click: ".impl-items .srclink"
assert-document-property-false: {"URL": |url|}
-Z threads=val -- use a thread pool with N threads
-Z time-llvm-passes=val -- measure time of each LLVM pass (default: no)
-Z time-passes=val -- measure time of each rustc pass (default: no)
+ -Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
-Z track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
-<section id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedconstant.YOLO" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
-<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
+<section id="associatedconstant.X" class="associatedconstant"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
-<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section>
\ No newline at end of file
+<section id="method.new" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section>
\ No newline at end of file
-<section id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
+<section id="method.bar" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
-<section id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
+<section id="tymethod.foo" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
-<section id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.T" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
-<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
+<section id="associatedtype.Y" class="associatedtype"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
impl Foo {
// @has async_fn/struct.Foo.html
- // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
// taken from `tokio` as an example of a method that was particularly bad before
- // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+ // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
- // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
+ // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)"
pub async fn mut_self(&mut self) {}
}
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'const fn new()'
+// @has - '//*[@class="method"]' 'const fn new()'
pub struct Foo(usize);
impl Foo {
}
// @has foo/trait.Array.html
-// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//*[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
impl<T, const N: usize> Array for [T; N] {
type Item = T;
}
fn foo(foo: Self::Fuu);
}
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
impl<T: Bar<Fuu = u32>> Foo<T> {
pub fn new(t: T) -> Foo<T> {
Foo {
// @has issue_33054/impls/struct.Foo.html
// @has - '//h3[@class="code-header"]' 'impl Foo'
// @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
// @has - '//h3[@class="code-header"]' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
// blanket implementations.
// @has 'foo/struct.Whatever.html'
-// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1
pub trait Something<T> { }
pub struct Whatever;
// There are 3 impl blocks with public item and one that should not be displayed
// by default because it only contains private items (but not in this case because
// we used `--document-private-items`).
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+// @count - '//*[@class="impl"]' 'impl Foo' 4
// Impl block only containing private items should not be displayed unless the
// `--document-private-items` flag is used.
// There are 3 impl blocks with public item and one that should not be displayed
// because it only contains private items.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+// @count - '//*[@class="impl"]' 'impl Foo' 3
// Impl block only containing private items should not be displayed.
/// Private
/// Hello empty impl block!
impl Foo {}
// We ensure that this empty impl block without doc isn't rendered.
-// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1
+// @count - '//*[@class="impl"]' 'impl Foo' 1
impl Foo {}
// Just to ensure that empty trait impl blocks are rendered.
pub struct Foo<T> { field: T }
-// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
// @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
// "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for'
-// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
pub use rustdoc_nonreachable_impls::Foo;
pub trait Blah { }
// @count issue_21474/struct.What.html \
-// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
pub struct What;
}
// @has issue_33302/struct.S.html \
- // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+ // '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
impl T<[i32; ($n * $n)]> for S {
}
// @has issue_33302/struct.S.html \
- // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+ // '//*[@class="impl"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
// @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
impl T<(i32,)> for S {
}
// @has issue_33302/struct.S.html \
- // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
+ // '//*[@class="impl"]' 'impl T<(i32, i32)> for S'
// @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
// @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
impl T<(i32, i32)> for S {
// @has 'foo/struct.Foo1.html'
pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
impl Bar<Foo1, &'static Foo1> for Foo1 {}
// @has 'foo/struct.Foo2.html'
pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
impl Bar<&'static Foo2, Foo2> for u8 {}
// @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
// @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
pub struct Switch<B: Signal> {
pub inner: <B as Signal2>::Item2,
}
}
// @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}
// @has issue_53812/trait.MyIterator.html
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>'
array_impls! { 10 3 2 1 0 }
pub trait ScopeHandle<'scope> {}
// @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
pub struct ScopeFutureContents<'scope, S>
where S: ScopeHandle<'scope>,
#![feature(negative_impls)]
// @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl !Sync for A"
pub struct A();
impl !Sync for A {}
// @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Send for B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Sync for B<T>"
pub struct B<T: ?Sized>(A, Box<T>);
}
// @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'a> Send for Parser<'a>"
pub struct Parser<'a> {
field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
{}
// @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Send for IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Sync for IntoIter<T>"
pub struct IntoIter<T>{
hello:DynTrait<FooInterface<T>>,
pub struct Struct {}
impl Struct {
- // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+ // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \
// 'pub const fn blurp() -> i32'
/// A useless function that always returns 1.
pub const fn blurp() -> i32 {
impl<T: Something> AnAmazingTrait for T {}
// @has 'issue_78673/struct.MyStruct.html'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
pub struct MyStruct;
impl AnAmazingTrait for MyStruct {}
// generic structs may have _both_ specific and blanket impls that apply
// @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
pub struct AnotherStruct<T>(T);
impl<T: Something> Something for AnotherStruct<T> {}
pub struct Foo;
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
// @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
impl Foo {
pub fn foo(mut self) {}
// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
pub struct Bravo<B>(B);
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \
// "impl !Send for Alpha"
impl !Send for Alpha {}
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\
// impl<B> !Send for Bravo<B>"
impl<B> !Send for Bravo<B> {}
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// There should be only one implementation listed.
-// @count - '//*[@class="impl has-srclink"]' 1
+// @count - '//*[@class="impl"]' 1
// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
// 'impl<A, B> Foo<&A> for &B'
#[doc(primitive = "reference")]
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
-// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
+// @has - '//*[@class="method"]' 'pub fn new()'
+// @has - '//*[@class="method"]' 'fn not_pub()'
pub struct Foo(usize);
impl Foo {
// @has basic/struct.Foo.html
// @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send'
// @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
pub struct Foo<T> {
field: T,
}
}
// @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
{}
// @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
// @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// 'impl<T> Sync for Foo<T>where T: Sync'
//
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// 'impl<T> Send for Foo<T>'
//
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
pub struct Foo<T> {
field: T,
}
}
// @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Send for Outer<T>"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> !Sync for Outer<T>"
pub struct Outer<T: Copy> {
inner_field: Inner<T>,
}
// @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// 'impl<T> Send for Foo<T>where T: Copy'
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// 'impl<T> Sync for Foo<T>where T: Sync'
pub struct Foo<T> {
inner_field: Inner<T>,
}
// @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> Send for Outer<T>where T: Send + Copy"
pub struct Outer<T> {
inner_field: Inner<T>,
}
// @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
// 'c: 'static,"
pub struct Foo<'c, K: 'c> {
// @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<P1> Send for WriteAndThen<P1>where <P1 as Pattern>::Value: Send"
pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
where P1: Pattern;
}
// @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
pub struct Owned<T> where T: OwnedTrait<'static> {
marker: <T as OwnedTrait<'static>>::Reader,
}
// @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias'
-// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias'
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
// @hasraw - 'Alias docstring'
// @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
pub struct Delta<D>(D);
-// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<D> Delta<D>where D: MyTrait"
impl<D> Delta<D> where D: MyTrait {
pub fn delta() {}
{ todo!() }
}
-// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<E> MyTrait for Echo<E>where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
// "impl<E> MyTrait for Echo<E>where E: MyTrait"
pub enum Foxtrot<F> { Foxtrot1(F) }
-// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \
// "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
// "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
error[E0080]: evaluation of constant value failed
- --> $DIR/infinite_loop.rs:6:15
+ --> $DIR/infinite_loop.rs:6:9
|
-LL | while n != 0 {
- | ^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | / while n != 0 {
+LL | |
+LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
+LL | | }
+ | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
error: aborting due to previous error
let _ = [(); {
let mut x = &0;
let mut n = 0;
- while n < 5 {
- n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
+ while n < 5 { //~ ERROR evaluation of constant value failed [E0080]
+ n = (n + 1) % 5;
x = &0; // Materialize a new AllocId
}
0
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-52475.rs:6:17
+ --> $DIR/issue-52475.rs:5:9
|
-LL | n = (n + 1) % 5;
- | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | / while n < 5 {
+LL | | n = (n + 1) % 5;
+LL | | x = &0; // Materialize a new AllocId
+LL | | }
+ | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`)
error: aborting due to previous error
--- /dev/null
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn foo() {}
+
+const fn call_foo() -> u32 {
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+
+ foo();
+ foo();
+ foo();
+ foo();
+ foo();
+
+ foo();
+ foo();
+ foo();
+ foo(); //~ ERROR evaluation of constant value failed [E0080]
+ 0
+}
+
+const X: u32 = call_foo();
+
+fn main() {
+ println!("{X}");
+}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ctfe-fn-call.rs:28:5
+ |
+LL | foo();
+ | ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+ |
+note: inside `call_foo`
+ --> $DIR/ctfe-fn-call.rs:28:5
+ |
+LL | foo();
+ | ^^^^^
+note: inside `X`
+ --> $DIR/ctfe-fn-call.rs:32:16
+ |
+LL | const X: u32 = call_foo();
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn labelled_loop(n: u32) -> u32 {
+ let mut i = 0;
+ 'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080]
+ if i > n {
+ break 'mylabel
+ }
+ i += 1;
+ }
+ 0
+}
+
+const X: u32 = labelled_loop(19);
+
+fn main() {
+ println!("{X}");
+}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ctfe-labelled-loop.rs:6:5
+ |
+LL | / 'mylabel: loop {
+LL | | if i > n {
+LL | | break 'mylabel
+LL | | }
+LL | | i += 1;
+LL | | }
+ | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+ |
+note: inside `labelled_loop`
+ --> $DIR/ctfe-labelled-loop.rs:6:5
+ |
+LL | / 'mylabel: loop {
+LL | | if i > n {
+LL | | break 'mylabel
+LL | | }
+LL | | i += 1;
+LL | | }
+ | |_____^
+note: inside `X`
+ --> $DIR/ctfe-labelled-loop.rs:15:16
+ |
+LL | const X: u32 = labelled_loop(19);
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+
+const fn recurse(n: u32) -> u32 {
+ if n == 0 {
+ n
+ } else {
+ recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080]
+ }
+}
+
+const X: u32 = recurse(19);
+
+fn main() {
+ println!("{X}");
+}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ctfe-recursion.rs:8:9
+ |
+LL | recurse(n - 1)
+ | ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+ |
+note: inside `recurse`
+ --> $DIR/ctfe-recursion.rs:8:9
+ |
+LL | recurse(n - 1)
+ | ^^^^^^^^^^^^^^
+note: [... 18 additional calls inside `recurse` ...]
+ --> $DIR/ctfe-recursion.rs:8:9
+ |
+LL | recurse(n - 1)
+ | ^^^^^^^^^^^^^^
+note: inside `X`
+ --> $DIR/ctfe-recursion.rs:12:16
+ |
+LL | const X: u32 = recurse(19);
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// check-fail
+// compile-flags: -Z tiny-const-eval-limit
+const fn simple_loop(n: u32) -> u32 {
+ let mut index = 0;
+ while index < n { //~ ERROR evaluation of constant value failed [E0080]
+ index = index + 1;
+ }
+ 0
+}
+
+const X: u32 = simple_loop(19);
+
+fn main() {
+ println!("{X}");
+}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ctfe-simple-loop.rs:5:5
+ |
+LL | / while index < n {
+LL | | index = index + 1;
+LL | | }
+ | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+ |
+note: inside `simple_loop`
+ --> $DIR/ctfe-simple-loop.rs:5:5
+ |
+LL | / while index < n {
+LL | | index = index + 1;
+LL | | }
+ | |_____^
+note: inside `X`
+ --> $DIR/ctfe-simple-loop.rs:11:16
+ |
+LL | const X: u32 = simple_loop(19);
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// check-pass
+//
+// Exercising an edge case which was found during Stage 2 compilation.
+// Compilation would fail for this code when running the `CtfeLimit`
+// MirPass (specifically when looking up the dominators).
+#![crate_type="lib"]
+
+const DUMMY: Expr = Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ path: Vec::new(),
+});
+
+pub enum Expr {
+ Path(ExprPath),
+}
+pub struct ExprPath {
+ pub attrs: Vec<()>,
+ pub path: Vec<()>,
+}
error[E0080]: evaluation of constant value failed
- --> $DIR/const_eval_limit_reached.rs:6:11
+ --> $DIR/const_eval_limit_reached.rs:6:5
|
-LL | while x != 1000 {
- | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | / while x != 1000 {
+LL | |
+LL | | x += 1;
+LL | | }
+ | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
error: aborting due to previous error
-> ::core::option::Option<::core::cmp::Ordering> {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
- match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
- ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
- match (self, other) {
- (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
- ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
- (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
- d1: __arg1_0, d2: __arg1_1 }) =>
- match ::core::cmp::PartialOrd::partial_cmp(__self_0,
- __arg1_0) {
- ::core::option::Option::Some(::core::cmp::Ordering::Equal)
- => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
- cmp => cmp,
- },
- _ =>
- ::core::option::Option::Some(::core::cmp::Ordering::Equal),
+ match (self, other) {
+ (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
+ ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+ (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
+ d1: __arg1_0, d2: __arg1_1 }) =>
+ match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0)
+ {
+ ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+ => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
+ cmp => cmp,
},
- cmp => cmp,
+ _ =>
+ ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+ &__arg1_tag),
}
}
}
-> ::core::option::Option<::core::cmp::Ordering> {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
- match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
- ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
- match (self, other) {
- (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
- ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
- (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
- ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
- (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
- ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
- _ => unsafe { ::core::intrinsics::unreachable() }
- },
- cmp => cmp,
+ match (self, other) {
+ (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
+ ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+ (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
+ ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+ (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
+ ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+ _ =>
+ ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+ &__arg1_tag),
}
}
}
--- /dev/null
+// check-pass
+
+#![deny(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+#![warn(multiple_supertrait_upcastable)]
+//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+//~| WARNING unknown lint: `multiple_supertrait_upcastable`
+
+fn main() {}
--- /dev/null
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+ |
+LL | #![deny(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+ = note: `#[warn(unknown_lints)]` on by default
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+ |
+LL | #![warn(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+ |
+LL | #![deny(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+ |
+LL | #![warn(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
+ |
+LL | #![deny(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: unknown lint: `multiple_supertrait_upcastable`
+ --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+ |
+LL | #![warn(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the `multiple_supertrait_upcastable` lint is unstable
+ = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
+
+warning: 6 warnings emitted
+
NonZeroIsize
and 21 others
= note: required for `&str` to implement `UpperHex`
-note: required by a bound in `ArgumentV1::<'a>::new_upper_hex`
+note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex`
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
= note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info)
| |
| required by a bound introduced by this call
|
- = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
+ = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
= note: required because it appears within the type `&core::fmt::Opaque`
= note: required because it appears within the type `ArgumentV1<'_>`
= note: required because it appears within the type `[ArgumentV1<'_>]`
- = note: required for `&[ArgumentV1<'_>]` to implement `Send`
+ = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send`
= note: required because it appears within the type `Arguments<'_>`
note: required by a bound in `send`
--> $DIR/send-sync.rs:1:12
--- /dev/null
+fn main() {
+ let x = 42;
+ match x {
+ 0..=73 => {},
+ 74..=> {}, //~ ERROR unexpected `=>` after open range
+ //~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
+ }
+}
--- /dev/null
+error: unexpected `=>` after open range
+ --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
+ |
+LL | 74..=> {},
+ | ^^^
+ |
+help: add a space between the pattern and `=>`
+ |
+LL | 74.. => {},
+ | +
+
+error: expected one of `=>`, `if`, or `|`, found `>`
+ --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
+ |
+LL | 74..=> {},
+ | ^ expected one of `=>`, `if`, or `|`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// build-pass
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn f(a: u32) -> u32 {
+ mir!(
+ let x: u32;
+ {
+ // Previously code generation failed with ICE "use of .. before def ..." because the
+ // definition of x was incorrectly identified as dominating the use of x located in the
+ // same statement:
+ x = x + a;
+ RET = x;
+ Return()
+ }
+ )
+}
--- /dev/null
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+ let mut uwu = ();
+ let mut r = Pin::new(&mut uwu);
+ foo(r.as_mut().get_mut());
+ foo(r.get_mut()); //~ ERROR use of moved value
+}
--- /dev/null
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+ let mut uwu = ();
+ let mut r = Pin::new(&mut uwu);
+ foo(r.get_mut());
+ foo(r.get_mut()); //~ ERROR use of moved value
+}
--- /dev/null
+error[E0382]: use of moved value: `r`
+ --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9
+ |
+LL | let mut r = Pin::new(&mut uwu);
+ | ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait
+LL | foo(r.get_mut());
+ | --------- `r` moved due to this method call
+LL | foo(r.get_mut());
+ | ^ value used here after move
+ |
+note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r`
+ --> $SRC_DIR/core/src/pin.rs:LL:COL
+help: consider reborrowing the `Pin` instead of moving it
+ |
+LL | foo(r.as_mut().get_mut());
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
//~| ERROR at least one trait is required for an object type
help: remove the parentheses
|
LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {}
-LL + fn foo2(_: &dyn Drop + AsRef<str>) {}
+LL + fn foo2(_: &dyn Drop + AsRef<str>) {}
+ |
+
+error: incorrect braces around trait bounds
+ --> $DIR/trait-object-delimiters.rs:8:25
+ |
+LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+ | ^ ^
+ |
+help: remove the parentheses
+ |
+LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {}
+LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {}
|
error: expected parameter name, found `{`
- --> $DIR/trait-object-delimiters.rs:8:17
+ --> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^ expected parameter name
error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
- --> $DIR/trait-object-delimiters.rs:8:17
+ --> $DIR/trait-object-delimiters.rs:10:17
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| -^ expected one of 10 possible tokens
| help: missing `,`
error: expected identifier, found `<`
- --> $DIR/trait-object-delimiters.rs:12:17
+ --> $DIR/trait-object-delimiters.rs:14:17
|
LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
| ^ expected identifier
error: invalid `dyn` keyword
- --> $DIR/trait-object-delimiters.rs:14:25
+ --> $DIR/trait-object-delimiters.rs:16:25
|
LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
| ^^^ help: remove this keyword
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0224]: at least one trait is required for an object type
- --> $DIR/trait-object-delimiters.rs:8:13
+ --> $DIR/trait-object-delimiters.rs:10:13
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
| ^^^
error[E0225]: only auto traits can be used as additional traits in a trait object
- --> $DIR/trait-object-delimiters.rs:14:29
+ --> $DIR/trait-object-delimiters.rs:16:29
|
LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
| ---- ^^^^^^^^^^ additional non-auto trait
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
Some errors have detailed explanations: E0224, E0225.
For more information about an error, try `rustc --explain E0224`.
--- /dev/null
+// compile-flags: -Z unpretty=thir-flat
+// check-pass
+
+pub fn main() {}
--- /dev/null
+DefId(0:3 ~ thir_flat[45a6]::main):
+Thir {
+ arms: [],
+ blocks: [
+ Block {
+ targeted_by_break: false,
+ region_scope: Node(1),
+ opt_destruction_scope: None,
+ span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+ stmts: [],
+ expr: None,
+ safety_mode: Safe,
+ },
+ ],
+ exprs: [
+ Expr {
+ ty: (),
+ temp_lifetime: Some(
+ Node(2),
+ ),
+ span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+ kind: Block {
+ block: b0,
+ },
+ },
+ Expr {
+ ty: (),
+ temp_lifetime: Some(
+ Node(2),
+ ),
+ span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+ kind: Scope {
+ region_scope: Node(2),
+ lint_level: Explicit(
+ HirId(DefId(0:3 ~ thir_flat[45a6]::main).2),
+ ),
+ value: e0,
+ },
+ },
+ Expr {
+ ty: (),
+ temp_lifetime: Some(
+ Node(2),
+ ),
+ span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
+ kind: Scope {
+ region_scope: Destruction(2),
+ lint_level: Inherited,
+ value: e1,
+ },
+ },
+ ],
+ stmts: [],
+ params: [],
+}
+
--- /dev/null
+// check-pass
+// compile-flags: -Zunpretty=thir-tree
+
+enum Bar {
+ First,
+ Second,
+ Third,
+}
+
+enum Foo {
+ FooOne(Bar),
+ FooTwo,
+}
+
+fn has_match(foo: Foo) -> bool {
+ match foo {
+ Foo::FooOne(Bar::First) => true,
+ Foo::FooOne(_) => false,
+ Foo::FooTwo => true,
+ }
+}
+
+fn main() {}
--- /dev/null
+DefId(0:16 ~ thir_tree_match[3c9a]::has_match):
+params: [
+ Param {
+ ty: Foo
+ ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
+ self_kind: None
+ hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1))
+ param: Some(
+ Pat: {
+ ty: Foo
+ span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
+ kind: PatKind {
+ Binding {
+ mutability: Not
+ name: "foo"
+ mode: ByValue
+ var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+ ty: Foo
+ is_primary: true
+ subpattern: None
+ }
+ }
+ }
+ )
+ }
+]
+body:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(26)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+ kind:
+ Scope {
+ region_scope: Node(26)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26))
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+ kind:
+ Block {
+ targeted_by_break: false
+ opt_destruction_scope: None
+ span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
+ region_scope: Node(25)
+ safety_mode: Safe
+ stmts: []
+ expr:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+ kind:
+ Scope {
+ region_scope: Node(3)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3))
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
+ kind:
+ Match {
+ scrutinee:
+ Expr {
+ ty: Foo
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+ kind:
+ Scope {
+ region_scope: Node(4)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4))
+ value:
+ Expr {
+ ty: Foo
+ temp_lifetime: Some(Node(26))
+ span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
+ kind:
+ VarRef {
+ id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+ }
+ }
+ }
+ }
+ arms: [
+ Arm {
+ pattern:
+ Pat: {
+ ty: Foo
+ span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
+ kind: PatKind {
+ Variant {
+ adt_def:
+ AdtDef {
+ did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+ variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+ flags: IS_ENUM
+ repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+ substs: []
+ variant_index: 0
+ subpatterns: [
+ Pat: {
+ ty: Bar
+ span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
+ kind: PatKind {
+ Variant {
+ adt_def:
+ AdtDef {
+ did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar)
+ variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }]
+ flags: IS_ENUM
+ repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 }
+ substs: []
+ variant_index: 0
+ subpatterns: []
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ guard: None
+ body:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(13))
+ span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(13)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(13))
+ span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+ kind:
+ Scope {
+ region_scope: Node(13)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13))
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(13))
+ span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
+ kind:
+ Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
+
+ }
+ }
+ }
+ }
+ }
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12))
+ scope: Node(12)
+ span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
+ }
+ Arm {
+ pattern:
+ Pat: {
+ ty: Foo
+ span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
+ kind: PatKind {
+ Variant {
+ adt_def:
+ AdtDef {
+ did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+ variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+ flags: IS_ENUM
+ repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+ substs: []
+ variant_index: 0
+ subpatterns: [
+ Pat: {
+ ty: Bar
+ span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
+ kind: PatKind {
+ Wild
+ }
+ }
+ ]
+ }
+ }
+ }
+ guard: None
+ body:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(19))
+ span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(19)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(19))
+ span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+ kind:
+ Scope {
+ region_scope: Node(19)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19))
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(19))
+ span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
+ kind:
+ Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
+
+ }
+ }
+ }
+ }
+ }
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18))
+ scope: Node(18)
+ span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
+ }
+ Arm {
+ pattern:
+ Pat: {
+ ty: Foo
+ span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
+ kind: PatKind {
+ Variant {
+ adt_def:
+ AdtDef {
+ did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo)
+ variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }]
+ flags: IS_ENUM
+ repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 }
+ substs: []
+ variant_index: 1
+ subpatterns: []
+ }
+ }
+ }
+ guard: None
+ body:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(24))
+ span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(24)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(24))
+ span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+ kind:
+ Scope {
+ region_scope: Node(24)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24))
+ value:
+ Expr {
+ ty: bool
+ temp_lifetime: Some(Node(24))
+ span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
+ kind:
+ Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
+
+ }
+ }
+ }
+ }
+ }
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23))
+ scope: Node(23)
+ span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+DefId(0:17 ~ thir_tree_match[3c9a]::main):
+params: [
+]
+body:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(2)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+ kind:
+ Scope {
+ region_scope: Node(2)
+ lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2))
+ value:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+ kind:
+ Block {
+ targeted_by_break: false
+ opt_destruction_scope: None
+ span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
+ region_scope: Node(1)
+ safety_mode: Safe
+ stmts: []
+ expr: []
+ }
+ }
+ }
+ }
+ }
+ }
+
+
--- /dev/null
+// compile-flags: -Z unpretty=thir-tree
+// check-pass
+
+pub fn main() {}
--- /dev/null
+DefId(0:3 ~ thir_tree[8f1d]::main):
+params: [
+]
+body:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+ kind:
+ Scope {
+ region_scope: Destruction(2)
+ lint_level: Inherited
+ value:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+ kind:
+ Scope {
+ region_scope: Node(2)
+ lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2))
+ value:
+ Expr {
+ ty: ()
+ temp_lifetime: Some(Node(2))
+ span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+ kind:
+ Block {
+ targeted_by_break: false
+ opt_destruction_scope: None
+ span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
+ region_scope: Node(1)
+ safety_mode: Safe
+ stmts: []
+ expr: []
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+++ /dev/null
-// compile-flags: -Z unpretty=thir-tree
-// check-pass
-
-pub fn main() {}
+++ /dev/null
-DefId(0:3 ~ thir_tree[8f1d]::main):
-Thir {
- arms: [],
- blocks: [
- Block {
- targeted_by_break: false,
- region_scope: Node(1),
- opt_destruction_scope: None,
- span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
- stmts: [],
- expr: None,
- safety_mode: Safe,
- },
- ],
- exprs: [
- Expr {
- ty: (),
- temp_lifetime: Some(
- Node(2),
- ),
- span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
- kind: Block {
- block: b0,
- },
- },
- Expr {
- ty: (),
- temp_lifetime: Some(
- Node(2),
- ),
- span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
- kind: Scope {
- region_scope: Node(2),
- lint_level: Explicit(
- HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
- ),
- value: e0,
- },
- },
- Expr {
- ty: (),
- temp_lifetime: Some(
- Node(2),
- ),
- span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
- kind: Scope {
- region_scope: Destruction(2),
- lint_level: Inherited,
- value: e1,
- },
- },
- ],
- stmts: [],
- params: [],
-}
-
--- /dev/null
+#![feature(multiple_supertrait_upcastable)]
+#![deny(multiple_supertrait_upcastable)]
+
+trait A {}
+trait B {}
+
+trait C: A + B {}
+//~^ ERROR `C` is object-safe and has multiple supertraits
+
+fn main() {}
--- /dev/null
+error: `C` is object-safe and has multiple supertraits
+ --> $DIR/multiple_supertrait_upcastable.rs:7:1
+ |
+LL | trait C: A + B {}
+ | ^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/multiple_supertrait_upcastable.rs:2:9
+ |
+LL | #![deny(multiple_supertrait_upcastable)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+