diff options
339 files changed, 6301 insertions, 1509 deletions
diff --git a/.gitignore b/.gitignore index ce797a7a837..04d2597ecc6 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ no_llvm_build /llvm/ /mingw-build/ build/ +!/compiler/rustc_mir_build/src/build/ /build-rust-analyzer/ /dist/ /unicode-downloads diff --git a/Cargo.lock b/Cargo.lock index 49b89c71994..1d40b8acc66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1365,9 +1365,9 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 3a0af04f9eb..3893875e9a4 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -259,7 +259,6 @@ pub enum ExprPrecedence { Assign, AssignOp, - Box, AddrOf, Let, Unary, @@ -319,8 +318,7 @@ impl ExprPrecedence { ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8, // Unary, prefix - ExprPrecedence::Box - | ExprPrecedence::AddrOf + ExprPrecedence::AddrOf // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. // However, this is not exactly right. When `let _ = a` is the LHS of a binop we // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 905d8c42b28..dbf15a3e05f 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -255,7 +255,7 @@ fn sccs_info<'cx, 'tcx>( let var_to_origin = infcx.reg_var_to_origin.borrow(); let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>(); - var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0)); + var_to_origin_sorted.sort_by_key(|vto| vto.0); let mut debug_str = "region variables to origins:\n".to_string(); for (reg_var, origin) in var_to_origin_sorted.into_iter() { debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); @@ -2216,7 +2216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // is in the same SCC or something. In that case, find what // appears to be the most interesting point to report to the // user via an even more ad-hoc guess. - categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); + categorized_path.sort_by_key(|p| p.category); debug!("sorted_path={:#?}", categorized_path); (categorized_path.remove(0), extra_info) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index d0af3729b23..1b8e9312e2f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -346,17 +346,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { crate::abi::codegen_return(fx); } TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => { - if !fx.tcx.sess.overflow_checks() { - let overflow_not_to_check = match msg { - AssertKind::OverflowNeg(..) => true, - AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; - if overflow_not_to_check { - let target = fx.get_block(*target); - fx.bcx.ins().jump(target, &[]); - continue; - } + if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { + let target = fx.get_block(*target); + fx.bcx.ins().jump(target, &[]); + continue; } let cond = codegen_operand(fx, cond).load_scalar(fx); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 64742bbb986..6a0d0ca55c2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1199,7 +1199,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) .unwrap_or(stem); - // GCC can have an optional target prefix. + // GCC/Clang can have an optional target prefix. let flavor = if stem == "emcc" { LinkerFlavor::EmCc } else if stem == "gcc" @@ -1207,7 +1207,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { || stem == "g++" || stem.ends_with("-g++") || stem == "clang" + || stem.ends_with("-clang") || stem == "clang++" + || stem.ends_with("-clang++") { LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target) } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") { diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs index 0f6e6032f9b..c34f1dbf856 100644 --- a/compiler/rustc_codegen_ssa/src/glue.rs +++ b/compiler/rustc_codegen_ssa/src/glue.rs @@ -46,7 +46,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul` // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication // cannot signed wrap, and that both operands are non-negative. But at the time of writing, - // `BuilderMethods` can't do this, and it doesn't seem to enable any further optimizations. + // the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations. bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())), bx.const_usize(unit.align.abi.bytes()), ) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 71c71d59b7a..f9aa2aecf65 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -563,15 +563,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // with #[rustc_inherit_overflow_checks] and inlined from // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() { - let overflow_not_to_check = match msg { - AssertKind::OverflowNeg(..) => true, - AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; - if overflow_not_to_check { - const_cond = Some(expected); - } + if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { + const_cond = Some(expected); } // Don't codegen the panic block if success if known. diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 92fa59aec6e..c134d3a6b2f 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -155,7 +155,7 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually /// check for overflow. - fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + fn ignore_optional_overflow_checks(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Entry point for obtaining the MIR of anything that should get evaluated. /// So not just functions and shims, but also const/static initializers, anonymous @@ -474,7 +474,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn ignore_checkable_overflow_assertions(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { false } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 685a5599cde..c2d1bc11c37 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -138,12 +138,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Assert { ref cond, expected, ref msg, target, cleanup } => { - let ignored = M::ignore_checkable_overflow_assertions(self) - && match msg { - mir::AssertKind::OverflowNeg(..) => true, - mir::AssertKind::Overflow(op, ..) => op.is_checkable(), - _ => false, - }; + let ignored = + M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check(); let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; if ignored || expected == cond_val { self.go_to_block(target); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 29cb2c0a33e..f2a904a6654 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" arrayvec = { version = "0.7", default-features = false } bitflags = "1.2.1" cfg-if = "1.0" -ena = "0.14.1" +ena = "0.14.2" indexmap = { version = "1.9.1" } jobserver_crate = { version = "0.1.13", package = "jobserver" } libc = "0.2" diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 91abdaadabd..27a869eb7cd 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -97,7 +97,17 @@ pub trait ObligationProcessor { type Error: Debug; type OUT: OutcomeTrait<Obligation = Self::Obligation, Error = Error<Self::Obligation, Self::Error>>; - fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool; + /// Implementations can provide a fast-path to obligation-processing + /// by counting the prefix of the passed iterator for which + /// `needs_process_obligation` would return false. + fn skippable_obligations<'a>( + &'a self, + _it: impl Iterator<Item = &'a Self::Obligation>, + ) -> usize { + 0 + } + + fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool; fn process_obligation( &mut self, @@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> { loop { let mut has_changed = false; + // This is the super fast path for cheap-to-check conditions. + let mut index = + processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation)); + // Note that the loop body can append new nodes, and those new nodes // will then be processed by subsequent iterations of the loop. // @@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> { // `for index in 0..self.nodes.len() { ... }` because the range would // be computed with the initial length, and we would miss the appended // nodes. Therefore we use a `while` loop. - let mut index = 0; while let Some(node) = self.nodes.get_mut(index) { - // This test is extremely hot. + // This is the moderately fast path when the prefix skipping above didn't work out. if node.state.get() != NodeState::Pending || !processor.needs_process_obligation(&node.obligation) { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index df857be85ad..d104ff0891d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -513,6 +513,7 @@ E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), +E0794: include_str!("./error_codes/E0794.md"), } // Undocumented removed error codes. Note that many removed error codes are documented. diff --git a/compiler/rustc_error_codes/src/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md index 4405a2149ce..9e85234bdbb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0206.md +++ b/compiler/rustc_error_codes/src/error_codes/E0206.md @@ -1,5 +1,5 @@ -The `Copy` trait was implemented on a type which is neither a struct nor an -enum. +The `Copy` trait was implemented on a type which is neither a struct, an +enum, nor a union. Erroneous code example: @@ -10,6 +10,6 @@ struct Bar; impl Copy for &'static mut Bar { } // error! ``` -You can only implement `Copy` for a struct or an enum. +You can only implement `Copy` for a struct, an enum, or a union. The previous example will fail because `&'static mut Bar` -is not a struct or enum. +is not a struct, an enum, or a union. diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md new file mode 100644 index 00000000000..a33802885c0 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -0,0 +1,64 @@ +A lifetime parameter of a function definition is called *late-bound* if it both: + +1. appears in an argument type +2. does not appear in a generic type constraint + +You cannot specify lifetime arguments for late-bound lifetime parameters. + +Erroneous code example: + +```compile_fail,E0794 +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo::<'static>; +``` + +The type of a concrete instance of a generic function is universally quantified +over late-bound lifetime parameters. This is because we want the function to +work for any lifetime substituted for the late-bound lifetime parameter, no +matter where the function is called. Consequently, it doesn't make sense to +specify arguments for late-bound lifetime parameters, since they are not +resolved until the function's call site(s). + +To fix the issue, remove the specified lifetime: + +``` +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo; +``` + +### Additional information + +Lifetime parameters that are not late-bound are called *early-bound*. +Confusion may arise from the fact that late-bound and early-bound +lifetime parameters are declared the same way in function definitions. +When referring to a function pointer type, universal quantification over +late-bound lifetime parameters can be made explicit: + +``` +trait BarTrait<'a> {} + +struct Bar<'a> { + s: &'a str +} + +impl<'a> BarTrait<'a> for Bar<'a> {} + +fn bar<'a, 'b, T>(x: &'a str, _t: T) -> &'a str +where T: BarTrait<'b> +{ + x +} + +let bar_fn: for<'a> fn(&'a str, Bar<'static>) -> &'a str = bar; // OK +let bar_fn2 = bar::<'static, Bar>; // Not allowed +let bar_fn3 = bar::<Bar>; // OK +``` + +In the definition of `bar`, the lifetime parameter `'a` is late-bound, while +`'b` is early-bound. This is reflected in the type annotation for `bar_fn`, +where `'a` is universally quantified and `'b` is substituted by a specific +lifetime. It is not allowed to explicitly specify early-bound lifetime +arguments when late-bound lifetime parameters are present (as for `bar_fn2`, +see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the +types that are constrained by early-bound parameters can be specified (as for +`bar_fn3`). diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index b1d9cea2773..6bc393c6534 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -245,12 +245,24 @@ pub(super) fn emit_frag_parse_err( e.note( "the macro call doesn't expand to an expression, but it can expand to a statement", ); - e.span_suggestion_verbose( - site_span.shrink_to_hi(), - "add `;` to interpret the expansion as a statement", - ";", - Applicability::MaybeIncorrect, - ); + + if parser.token == token::Semi { + if let Ok(snippet) = parser.sess.source_map().span_to_snippet(site_span) { + e.span_suggestion_verbose( + site_span, + "surround the macro invocation with `{}` to interpret the expansion as a statement", + format!("{{ {}; }}", snippet), + Applicability::MaybeIncorrect, + ); + } + } else { + e.span_suggestion_verbose( + site_span.shrink_to_hi(), + "add `;` to interpret the expansion as a statement", + ";", + Applicability::MaybeIncorrect, + ); + } } }, _ => annotate_err_with_kind(&mut e, kind, site_span), diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ac93dd555b7..3d644de1665 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -91,7 +91,7 @@ declare_features! ( /// Allows coercing non capturing closures to function pointers. (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), /// Allows using the CMPXCHG16B target feature. - (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None), + (accepted, cmpxchg16b_target_feature, "1.69.0", Some(44839), None), /// Allows usage of the `compile_error!` macro. (accepted, compile_error, "1.20.0", Some(40872), None), /// Allows `impl Trait` in function return types. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index c893b34b4ac..e0a7c864b94 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -161,7 +161,7 @@ declare_features! ( /// 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), + (active, multiple_supertrait_upcastable, "1.69.0", 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. @@ -214,7 +214,7 @@ declare_features! ( /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (active, needs_panic_runtime, "1.10.0", Some(32837), None), /// Allows using `+bundled,+whole-archive` native libs. - (active, packed_bundled_libs, "CURRENT_RUSTC_VERSION", Some(108081), None), + (active, packed_bundled_libs, "1.69.0", Some(108081), None), /// Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), /// Allows using `#[rustc_allow_const_fn_unstable]`. @@ -468,7 +468,7 @@ declare_features! ( /// Allows using the `non_exhaustive_omitted_patterns` lint. (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), /// Allows `for<T>` binders in where-clauses - (incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(108185), None), + (incomplete, non_lifetime_binders, "1.69.0", Some(108185), None), /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f00a5f24e45..f4b46b9a131 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1673,7 +1673,6 @@ pub struct Expr<'hir> { impl Expr<'_> { pub fn precedence(&self) -> ExprPrecedence { match self.kind { - ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, @@ -1763,7 +1762,6 @@ impl Expr<'_> { | ExprKind::Lit(_) | ExprKind::ConstBlock(..) | ExprKind::Unary(..) - | ExprKind::Box(..) | ExprKind::AddrOf(..) | ExprKind::Binary(..) | ExprKind::Yield(..) @@ -1851,7 +1849,6 @@ impl Expr<'_> { | ExprKind::InlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::ConstBlock(..) - | ExprKind::Box(..) | ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::DropTemps(..) @@ -1862,8 +1859,7 @@ impl Expr<'_> { /// To a first-order approximation, is this a pattern? pub fn is_approximately_pattern(&self) -> bool { match &self.kind { - ExprKind::Box(_) - | ExprKind::Array(_) + ExprKind::Array(_) | ExprKind::Call(..) | ExprKind::Tup(_) | ExprKind::Lit(_) @@ -1910,8 +1906,6 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { #[derive(Debug, HashStable_Generic)] pub enum ExprKind<'hir> { - /// A `box x` expression. - Box(&'hir Expr<'hir>), /// Allow anonymous constants from an inline `const` block ConstBlock(AnonConst), /// An array (e.g., `[a, b, c, d]`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cc0f64017e4..234256ab553 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -682,7 +682,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { visitor.visit_id(expression.hir_id); match expression.kind { - ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 2f4963f6bc3..3b5c67de239 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -612,7 +612,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - let mut err = tcx.sess.struct_span_err(span, msg); + let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg); err.span_note(span_late, note); err.emit(); } else { diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index f830269b45d..2e788de9fab 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2396,13 +2396,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx, infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id), ); + // I guess we don't need to make a universe unless we need it, + // but also we're on the error path, so it doesn't matter here. + let universe = infcx.create_next_universe(); infcx .can_eq( ty::ParamEnv::empty(), impl_.self_ty(), - // Must fold past escaping bound vars too, - // since we have those at this point in astconv. - tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased), + tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_erased, + types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType { + universe, + name: bv.kind, + }), + consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst { + universe, + name: bv + }, ty), + }) ) }) && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative @@ -3317,10 +3328,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx, trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), ); + let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig); - let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() }; - - Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty)) + Some(if let Some(arg_idx) = arg_idx { + *fn_sig.inputs().get(arg_idx)? + } else { + fn_sig.output() + }) } #[instrument(level = "trace", skip(self, generate_err))] diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 14dc9d89180..872fec3954b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -557,7 +557,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_opaque(tcx, id); } DefKind::ImplTraitPlaceholder => { - let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id()); + let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id()); // Only check the validity of this opaque type if the function has a default body if let hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6e6f8c1533b..32b6aeed5f8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1205,6 +1205,17 @@ fn compare_number_of_generics<'tcx>( return Ok(()); } + // We never need to emit a separate error for RPITITs, since if an RPITIT + // has mismatched type or const generic arguments, then the method that it's + // inheriting the generics from will also have mismatched arguments, and + // we'll report an error for that instead. Delay a bug for safety, though. + if tcx.opt_rpitit_info(trait_.def_id).is_some() { + return Err(tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + "errors comparing numbers of generics of trait/impl functions were not emitted", + )); + } + let matchings = [ ("type", trait_own_counts.types, impl_own_counts.types), ("const", trait_own_counts.consts, impl_own_counts.consts), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 71050864ce0..4120ad45f6a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,7 +1,6 @@ use crate::autoderef::Autoderef; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use hir::def::DefKind; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -1548,16 +1547,27 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) && assoc_item.container == ty::AssocItemContainer::TraitContainer { + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering + // strategy, we can't just call `check_associated_item` on the new RPITITs, + // because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. + // That's because we need to check that the bounds of the RPITIT hold using + // the special substs that we create during opaque type lowering, otherwise we're + // getting a bunch of early bound and free regions mixed up... Haven't looked too + // deep into this, though. for arg in fn_output.walk() { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, proj) = ty.kind() - && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder - && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id() + // RPITITs are always eagerly normalized into opaques, so always look for an + // opaque here. + && let ty::Alias(ty::Opaque, opaque_ty) = ty.kind() + && let Some(opaque_def_id) = opaque_ty.def_id.as_local() + && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && source == fn_def_id { - let span = tcx.def_span(proj.def_id); - let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id); + let span = tcx.def_span(opaque_ty.def_id); + let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs); + let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs); let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( wfcx.infcx, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 7dce29cc0bb..df0258ff7a3 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -3,7 +3,7 @@ use crate::astconv::AstConv; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::Span; @@ -76,18 +76,26 @@ pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: DefId, ) -> &'_ [(ty::Predicate<'_>, Span)] { - // If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that - // generated the synthesized associate type. - let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) = - tcx.opt_rpitit_info(def_id) - { - Some(opaque_def_id) - } else { - None - }; + match tcx.opt_rpitit_info(def_id) { + // RPITIT's bounds are the same as opaque type bounds, but with + // a projection self type. + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); + let opaque_ty = item.expect_opaque_ty(); + return opaque_type_bounds( + tcx, + opaque_def_id, + opaque_ty.bounds, + tcx.mk_projection(def_id, ty::InternalSubsts::identity_for_item(tcx, def_id)), + item.span, + ); + } + // These should have been fed! + Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(), + None => {} + } - let bounds_def_id = rpitit_info.unwrap_or(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), @@ -100,12 +108,12 @@ pub(super) fn explicit_item_bounds( .. }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let item_ty = if *in_trait || rpitit_info.is_some() { + let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) }; - opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span) + opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index a8b7699b667..361e8948e85 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -112,10 +112,14 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if matches!( - self.tcx.def_kind(*def_id), - DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - ) => + if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) => + { + self.visit_opaque(*def_id, substs) + } + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary + // at all for RPITITs. + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + if self.tcx.is_impl_trait_in_trait(*def_id) => { self.visit_opaque(*def_id, substs) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d715b03e40e..63ea6c90477 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1366,10 +1366,6 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { - hir::ExprKind::Box(expr) => { - self.word_space("Box::new"); - self.print_call_post(std::slice::from_ref(expr)); - } hir::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e19ef2ff3bf..035ccf30b24 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // check that the `if` expr without `else` is the fn body's expr if expr.span == sp { - return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| { + return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| { let span = fn_decl.output.span(); let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?; Some((span, format!("expected `{snippet}` because of this return type"))) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 6becf4892ac..ec391ea80f4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -2,7 +2,6 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; -use hir::def::DefKind; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; @@ -715,14 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .subst_iter_copied(self.tcx, substs) .find_map(|(p, s)| get_future_output(p, s))?, ty::Error(_) => return None, - ty::Alias(ty::Projection, proj) - if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => - { - self.tcx - .bound_explicit_item_bounds(proj.def_id) - .subst_iter_copied(self.tcx, proj.substs) - .find_map(|(p, s)| get_future_output(p, s))? - } + ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self + .tcx + .bound_explicit_item_bounds(proj.def_id) + .subst_iter_copied(self.tcx, proj.substs) + .find_map(|(p, s)| get_future_output(p, s))?, _ => span_bug!( self.tcx.def_span(expr_def_id), "async fn generator return type not an inference variable: {ret_ty}" diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 3d6274ede81..a27905ea46c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1722,12 +1722,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); } } - fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + fcx.get_node_fn_decl(parent) + .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) } else { fcx.get_fn_decl(parent_id) }; - if let Some((fn_decl, can_suggest)) = fn_decl { + if let Some((fn_id, fn_decl, can_suggest)) = fn_decl { if blk_id.is_none() { pointing_at_return_type |= fcx.suggest_missing_return_type( &mut err, @@ -1735,7 +1736,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expected, found, can_suggest, - fcx.tcx.hir().get_parent_item(id).into(), + fn_id, ); } if !pointing_at_return_type { @@ -1746,17 +1747,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let parent_id = fcx.tcx.hir().get_parent_item(id); let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id); - if let (Some(expr), Some(_), Some((fn_decl, _, _))) = + if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) = (expression, blk_id, fcx.get_node_fn_decl(parent_item)) { fcx.suggest_missing_break_or_return_expr( - &mut err, - expr, - fn_decl, - expected, - found, - id, - parent_id.into(), + &mut err, expr, fn_decl, expected, found, id, fn_id, ); } @@ -1882,7 +1877,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { - if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) + if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id) && let hir::FnRetTy::Return(ty) = fn_decl.output && let ty = fcx.astconv().ast_ty_to_ty( ty) && let ty::Dynamic(..) = ty.kind() diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index afef331ec1d..29db16849dd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -284,7 +284,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { - ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected), ExprKind::Lit(ref lit) => self.check_lit(&lit, expected), ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { @@ -359,16 +358,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() { - ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()), - _ => NoExpectation, - }); - let referent_ty = self.check_expr_with_expectation(expr, expected_inner); - self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType); - self.tcx.mk_box(referent_ty) - } - fn check_expr_unary( &self, unop: hir::UnOp, @@ -799,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ret_coercion_span.set(Some(expr.span)); } let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) { + if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) { coercion.coerce_forced_unit( self, &cause, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index b9a058d6bba..9aa6c7f103f 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -356,10 +356,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.walk_captures(closure); } - hir::ExprKind::Box(ref base) => { - self.consume_expr(base); - } - hir::ExprKind::Yield(value, _) => { self.consume_expr(value); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index e539693402a..8455076de56 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -898,51 +898,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. + /// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure + /// that is the child of a function, return that function's `HirId` and `FnDecl` instead. + /// This may seem confusing at first, but this is used in diagnostics for `async fn`, + /// for example, where most of the type checking actually happens within a nested closure, + /// but we often want access to the parent function's signature. + /// + /// Otherwise, return false. pub(in super::super) fn get_node_fn_decl( &self, node: Node<'tcx>, - ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> { match node { - Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { + Node::Item(&hir::Item { + ident, + kind: hir::ItemKind::Fn(ref sig, ..), + owner_id, + .. + }) => { // This is less than ideal, it will not suggest a return type span on any // method called `main`, regardless of whether it is actually the entry point, // but it will still present it as the reason for the expected type. - Some((&sig.decl, ident, ident.name != sym::main)) + Some(( + hir::HirId::make_owner(owner_id.def_id), + &sig.decl, + ident, + ident.name != sym::main, + )) } Node::TraitItem(&hir::TraitItem { ident, kind: hir::TraitItemKind::Fn(ref sig, ..), + owner_id, .. - }) => Some((&sig.decl, ident, true)), + }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)), Node::ImplItem(&hir::ImplItem { ident, kind: hir::ImplItemKind::Fn(ref sig, ..), + owner_id, .. - }) => Some((&sig.decl, ident, false)), - Node::Expr(&hir::Expr { - hir_id, - kind: hir::ExprKind::Closure(..), - .. - }) if let Some(Node::Item(&hir::Item { + }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)), + Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. }) + if let Some(Node::Item(&hir::Item { + ident, + kind: hir::ItemKind::Fn(ref sig, ..), + owner_id, + .. + })) = self.tcx.hir().find_parent(hir_id) => Some(( + hir::HirId::make_owner(owner_id.def_id), + &sig.decl, ident, - kind: hir::ItemKind::Fn(ref sig, ..), - .. - })) = self.tcx.hir().find_parent(hir_id) => { - Some((&sig.decl, ident, ident.name != sym::main)) - }, + ident.name != sym::main, + )), _ => None, } } - /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a + /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a /// suggestion can be made, `None` otherwise. - pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { + pub fn get_fn_decl( + &self, + blk_id: hir::HirId, + ) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { let parent = self.tcx.hir().get(blk_id); - self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + self.get_node_fn_decl(parent) + .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) }) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7064ff65384..61338ac613a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id); - self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) + self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident)) } /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 690d8a23826..7a09ea40d79 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); self.suggest_missing_semicolon(err, expr, expected, false); let mut pointing_at_return_type = false; - if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap(); + if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { pointing_at_return_type = self.suggest_missing_return_type( err, &fn_decl, diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 7c0402b1c7f..1eeb7d984ee 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -190,7 +190,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { // // Some of these may be interesting in the future ExprKind::Path(..) - | ExprKind::Box(..) | ExprKind::ConstBlock(..) | ExprKind::Array(..) | ExprKind::Call(..) @@ -478,7 +477,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { | ExprKind::AssignOp(..) | ExprKind::Binary(..) | ExprKind::Block(..) - | ExprKind::Box(..) | ExprKind::Cast(..) | ExprKind::Closure { .. } | ExprKind::ConstBlock(..) diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 4d3969d28aa..9a8d7ca9e33 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -382,7 +382,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)), } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 8f31a79e7b3..b6d39341fe7 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1028,6 +1028,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { true } }) + // ensure that we don't suggest unstable methods + .filter(|candidate| { + // note that `DUMMY_SP` is ok here because it is only used for + // suggestions and macro stuff which isn't applicable here. + !matches!( + self.tcx.eval_stability(candidate.item.def_id, None, DUMMY_SP, None), + stability::EvalResult::Deny { .. } + ) + }) .map(|candidate| candidate.item.ident(self.tcx)) .filter(|&name| set.insert(name)) .collect(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ac4986a577c..fd16363a1db 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -359,10 +359,12 @@ impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { let (def_id, substs) = match *ty.kind() { ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if matches!( - self.tcx.def_kind(def_id), - DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - ) => + if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) => + { + (def_id, substs) + } + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) + if self.tcx.is_impl_trait_in_trait(def_id) => { (def_id, substs) } @@ -613,9 +615,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| { - // Only external crates, if either is from a local - // module we could have false positives - if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { + // Only report definitions from different crates. If both definitions + // are from a local module we could have false positives, e.g. + // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; + if did1.krate != did2.krate { let abs_path = |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]); @@ -627,10 +630,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if same_path().unwrap_or(false) { let crate_name = self.tcx.crate_name(did1.krate); - err.note(&format!( - "perhaps two different versions of crate `{}` are being used?", - crate_name - )); + let msg = if did1.is_local() || did2.is_local() { + format!( + "the crate `{crate_name}` is compiled multiple times, possibly with different configurations" + ) + } else { + format!( + "perhaps two different versions of crate `{crate_name}` are being used?" + ) + }; + err.note(msg); } } }; @@ -1757,8 +1766,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) } (true, ty::Alias(ty::Projection, proj)) - if self.tcx.def_kind(proj.def_id) - == DefKind::ImplTraitPlaceholder => + if self.tcx.is_impl_trait_in_trait(proj.def_id) => { let sm = self.tcx.sess.source_map(); let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index b33729d0be5..b38bbdfe7bb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -1,7 +1,7 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; -use rustc_hir::{self as hir, def::DefKind}; +use rustc_hir as hir; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; @@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag.note("an associated type was expected, but a different one was found"); } (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) - if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder => + if !tcx.is_impl_trait_in_trait(proj.def_id) => { let p_def_id = tcx .generics_of(body_owner_def_id) @@ -222,7 +222,7 @@ impl<T> Trait<T> for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { self.expected_projection( diag, proj_ty, @@ -231,7 +231,7 @@ impl<T> Trait<T> for X { cause.code(), ); } - (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { let msg = format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 96e7c095d34..aeb4ddb4212 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -188,6 +188,16 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] + fn try_type_variables_probe_ref( + &self, + vid: ty::TyVid, + ) -> Option<&type_variable::TypeVariableValue<'tcx>> { + // Uses a read-only view of the unification table, this way we don't + // need an undo log. + self.type_variable_storage.eq_relations_ref().try_probe_value(vid) + } + + #[inline] fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> { self.type_variable_storage.with_log(&mut self.undo_log) } @@ -1646,6 +1656,28 @@ impl<'tcx> InferCtxt<'tcx> { tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } + /// The returned function is used in a fast path. If it returns `true` the variable is + /// unchanged, `false` indicates that the status is unknown. + #[inline] + pub fn is_ty_infer_var_definitely_unchanged<'a>( + &'a self, + ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) { + // This hoists the borrow/release out of the loop body. + let inner = self.inner.try_borrow(); + + return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) { + (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { + use self::type_variable::TypeVariableValue; + + match inner.try_type_variables_probe_ref(ty_var) { + Some(TypeVariableValue::Unknown { .. }) => true, + _ => false, + } + } + _ => false, + }; + } + /// `ty_or_const_infer_var_changed` is equivalent to one of these two: /// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`) /// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index ed4bc594d1a..49f823a47b8 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -3,7 +3,6 @@ use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; -use hir::def::DefKind; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; use rustc_data_structures::sync::Lrc; @@ -478,9 +477,7 @@ where } } - ty::Alias(ty::Projection, proj) - if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder => - { + ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => { // Skip lifetime parameters that are not captures. let variances = self.tcx.variances_of(proj.def_id); @@ -559,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> { // FIXME(RPITIT): Don't replace RPITITs with inference vars. ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() - && tcx.def_kind(projection_ty.def_id) - != DefKind::ImplTraitPlaceholder => + && !tcx.is_impl_trait_in_trait(projection_ty.def_id) => { self.infer_projection( param_env, diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 263c6a47dd2..f7ab05b2d49 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> { ) -> TypeVariableTable<'a, 'tcx> { TypeVariableTable { storage: self, undo_log } } + + #[inline] + pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> { + &self.eq_relations + } } impl<'tcx> TypeVariableTable<'_, 'tcx> { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 68e62c9789a..c822237413c 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -508,3 +508,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass .specifically = this associated type bound is unsatisfied for `{$proj_ty}` lint_opaque_hidden_inferred_bound_sugg = add this bound + +lint_useless_anonymous_reexport = useless anonymous re-export + .note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}` diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b3578540516..c2cc2fcdf55 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -74,6 +74,7 @@ mod opaque_hidden_inferred_bound; mod pass_by_value; mod passes; mod redundant_semicolon; +mod reexports; mod traits; mod types; mod unused; @@ -111,6 +112,7 @@ use noop_method_call::*; use opaque_hidden_inferred_bound::*; use pass_by_value::*; use redundant_semicolon::*; +use reexports::*; use traits::*; use types::*; use unused::*; @@ -242,6 +244,7 @@ late_lint_methods!( OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, + UselessAnonymousReexport: UselessAnonymousReexport, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 308c02929ca..46a025f41e0 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1528,3 +1528,11 @@ pub struct UnusedAllocationDiag; #[derive(LintDiagnostic)] #[diag(lint_unused_allocation_mut)] pub struct UnusedAllocationMutDiag; + +#[derive(LintDiagnostic)] +#[diag(lint_useless_anonymous_reexport)] +#[note] +pub struct UselessAnonymousReexportDiag { + pub article: &'static str, + pub desc: &'static str, +} diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs new file mode 100644 index 00000000000..8737a57ea02 --- /dev/null +++ b/compiler/rustc_lint/src/reexports.rs @@ -0,0 +1,82 @@ +use crate::lints::UselessAnonymousReexportDiag; +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_middle::ty::Visibility; +use rustc_span::symbol::kw; +use rustc_span::Span; + +declare_lint! { + /// The `useless_anonymous_reexport` lint checks if anonymous re-exports + /// are re-exports of traits. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(useless_anonymous_reexport)] + /// + /// mod sub { + /// pub struct Bar; + /// } + /// + /// pub use self::sub::Bar as _; + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Anonymous re-exports are only useful if it's a re-export of a trait + /// in case you want to give access to it. If you re-export any other kind, + /// you won't be able to use it since its name won't be accessible. + pub USELESS_ANONYMOUS_REEXPORT, + Warn, + "useless anonymous re-export" +} + +declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]); + +fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) { + let article = cx.tcx.def_descr_article(def_id); + let desc = cx.tcx.def_descr(def_id); + cx.emit_spanned_lint( + USELESS_ANONYMOUS_REEXPORT, + span, + UselessAnonymousReexportDiag { article, desc }, + ); +} + +impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Use(path, kind) = item.kind && + !matches!(kind, UseKind::Glob) && + item.ident.name == kw::Underscore && + // We only want re-exports. If it's just a `use X;`, then we ignore it. + match cx.tcx.local_visibility(item.owner_id.def_id) { + Visibility::Public => true, + Visibility::Restricted(level) => { + level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id) + } + } + { + for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) { + match cx.tcx.def_kind(def_id) { + DefKind::Trait | DefKind::TraitAlias => {} + DefKind::TyAlias => { + let ty = cx.tcx.type_of(def_id); + if !ty.0.is_trait() { + emit_err(cx, item.span, def_id); + break; + } + } + _ => { + emit_err(cx, item.span, def_id); + break; + } + } + } + } + } +} diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9649ce2c5a7..c778574b2c5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1028,7 +1028,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::InlineConst => true, DefKind::ImplTraitPlaceholder => { - let parent_def_id = tcx.impl_trait_in_trait_parent(def_id.to_def_id()); + let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id()); let assoc_item = tcx.associated_item(parent_def_id); match assoc_item.container { // Always encode an RPIT in an impl fn, since it always has a body diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7d515bb0f5a..42c0354d03a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1268,6 +1268,13 @@ impl<'tcx> BasicBlockData<'tcx> { } impl<O> AssertKind<O> { + /// Returns true if this an overflow checking assertion controlled by -C overflow-checks. + pub fn is_optional_overflow_check(&self) -> bool { + use AssertKind::*; + use BinOp::*; + matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..)) + } + /// Getting a description does not require `O` to be printable, and does not /// require allocation. /// The caller is expected to handle `BoundsCheck` separately. @@ -1992,16 +1999,6 @@ impl BorrowKind { } } -impl BinOp { - /// The checkable operators are those whose overflow checking behavior is controlled by - /// -Coverflow-checks option. The remaining operators have either no overflow conditions (e.g., - /// BitAnd, BitOr, BitXor) or are always checked for overflow (e.g., Div, Rem). - pub fn is_checkable(self) -> bool { - use self::BinOp::*; - matches!(self, Add | Sub | Mul | Shl | Shr) - } -} - impl<'tcx> Debug for Rvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Rvalue::*; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index a28ecfa9bdc..b16b6616415 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -646,8 +646,7 @@ pub enum TerminatorKind<'tcx> { /// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR /// that is used for CTFE), the following variants of this terminator behave as `goto target`: /// - `OverflowNeg(..)`, - /// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT - /// div or rem). + /// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem. Assert { cond: Operand<'tcx>, expected: bool, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2cd79157441..c8860cc55f6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -191,6 +191,7 @@ rustc_queries! { { desc { "determine whether the opaque is a type-alias impl trait" } separate_provide_extern + feedable } query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6231dd9b6f5..fb3e9cb1263 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -305,8 +305,6 @@ pub enum ObligationCauseCode<'tcx> { SizedReturnType, /// Yield type must be `Sized`. SizedYieldType, - /// Box expression result type must be `Sized`. - SizedBoxType, /// Inline asm operand type must be `Sized`. InlineAsmSized, /// `[expr; N]` requires `type_of(expr): Copy`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 04d7de531c2..6ef8384d010 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2552,12 +2552,18 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } - pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId { - while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { - debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); - def_id = self.parent(def_id); + pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId { + match self.opt_rpitit_info(def_id) { + Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) + | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id, + None => { + while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { + debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); + def_id = self.parent(def_id); + } + def_id + } } - def_id } pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { @@ -2572,6 +2578,10 @@ impl<'tcx> TyCtxt<'tcx> { let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + if self.lower_impl_trait_in_trait_to_assoc_ty() { + return !self.associated_items_for_impl_trait_in_trait(trait_item_def_id).is_empty(); + } + // FIXME(RPITIT): This does a somewhat manual walk through the signature // of the trait fn to look for any RPITITs, but that's kinda doing a lot // of work. We can probably remove this when we refactor RPITITs to be diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b3139d23d36..fffdbfc9660 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -728,7 +728,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Alias(ty::Projection, ref data) => { if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) - && self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + && self.tcx().is_impl_trait_in_trait(data.def_id) { return self.pretty_print_opaque_impl_type(data.def_id, data.substs); } else { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52d114bae30..4c606b939b2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1288,7 +1288,7 @@ impl<'tcx> AliasTy<'tcx> { match tcx.def_kind(self.def_id) { DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), DefKind::ImplTraitPlaceholder => { - tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id)) + tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id)) } kind => bug!("expected a projection AliasTy; found {kind:?}"), } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 9f48986b1ad..140d1154718 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -73,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[lhs], LocalInfo::Boring, NeedsTemporary::Maybe) + block = this.as_operand( + block, + scope, + &this.thir[lhs], + LocalInfo::Boring, + NeedsTemporary::Maybe + ) ); let rhs = unpack!( - block = - this.as_operand(block, scope, &this.thir[rhs], LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[rhs], + LocalInfo::Boring, + NeedsTemporary::No + ) ); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { let arg = unpack!( - block = - this.as_operand(block, scope, &this.thir[arg], LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[arg], + LocalInfo::Boring, + NeedsTemporary::No + ) ); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { @@ -272,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Pointer { cast, source } => { let source = unpack!( - block = - this.as_operand(block, scope, &this.thir[source], LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + &this.thir[source], + LocalInfo::Boring, + NeedsTemporary::No + ) ); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } @@ -502,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant) )); - let operand = - unpack!(block = this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)); + let operand = unpack!( + block = + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + ); block.and(Rvalue::Use(operand)) } } @@ -662,8 +684,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` - let value_operand = - unpack!(block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)); + let value_operand = unpack!( + block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No) + ); if let Operand::Move(to_drop) = value_operand { let success = this.cfg.start_new_block(); this.cfg.terminate( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 22785dfd2ce..2d52102db2c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2252,7 +2252,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty: None, source_info, internal: false, - local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::RefForGuard))), + local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User( + BindingForm::RefForGuard, + ))), }); self.var_debug_info.push(VarDebugInfo { name, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 6814fd4cb35..80d8b27336c 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -876,21 +876,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; - **self.local_decls[local].local_info.as_mut().assert_crate_local() = if let Some(kind) = param.self_kind { - LocalInfo::User( - BindingForm::ImplicitSelf(kind), - ) - } else { - let binding_mode = ty::BindingMode::BindByValue(mutability); - LocalInfo::User(BindingForm::Var( - VarBindingForm { + **self.local_decls[local].local_info.as_mut().assert_crate_local() = + if let Some(kind) = param.self_kind { + LocalInfo::User(BindingForm::ImplicitSelf(kind)) + } else { + let binding_mode = ty::BindingMode::BindByValue(mutability); + LocalInfo::User(BindingForm::Var(VarBindingForm { binding_mode, opt_ty_info: param.ty_span, opt_match_place: Some((None, span)), pat_span: span, - }, - )) - }; + })) + }; self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 9086412c09a..cecb8a61aa2 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -780,7 +780,6 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::DropTemps(ref source) => { ExprKind::Use { source: self.mirror_expr(source) } } - hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) }, hir::ExprKind::Array(ref fields) => { ExprKind::Array { fields: self.mirror_exprs(fields) } } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index bd12087629c..486275570bd 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -655,26 +655,20 @@ where /// /// ```text /// loop-block: - /// can_go = cur == length_or_end + /// can_go = cur == len /// if can_go then succ else drop-block /// drop-block: - /// if ptr_based { - /// ptr = cur - /// cur = cur.offset(1) - /// } else { - /// ptr = &raw mut P[cur] - /// cur = cur + 1 - /// } + /// ptr = &raw mut P[cur] + /// cur = cur + 1 /// drop(ptr) /// ``` fn drop_loop( &mut self, succ: BasicBlock, cur: Local, - length_or_end: Place<'tcx>, + len: Local, ety: Ty<'tcx>, unwind: Unwind, - ptr_based: bool, ) -> BasicBlock { let copy = |place: Place<'tcx>| Operand::Copy(place); let move_ = |place: Place<'tcx>| Operand::Move(place); @@ -683,22 +677,19 @@ where let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut }); let ptr = Place::from(self.new_temp(ptr_ty)); let can_go = Place::from(self.new_temp(tcx.types.bool)); - let one = self.constant_usize(1); - let (ptr_next, cur_next) = if ptr_based { - ( - Rvalue::Use(copy(cur.into())), - Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))), - ) - } else { - ( - Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), - Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), - ) - }; let drop_block = BasicBlockData { - statements: vec![self.assign(ptr, ptr_next), self.assign(Place::from(cur), cur_next)], + statements: vec![ + self.assign( + ptr, + Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)), + ), + self.assign( + cur.into(), + Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), + ), + ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, @@ -711,10 +702,7 @@ where let loop_block = BasicBlockData { statements: vec![self.assign( can_go, - Rvalue::BinaryOp( - BinOp::Eq, - Box::new((copy(Place::from(cur)), copy(length_or_end))), - ), + Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { @@ -738,13 +726,6 @@ where fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock { debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); - - // if size_of::<ety>() == 0 { - // index_based_loop - // } else { - // ptr_based_loop - // } - let tcx = self.tcx(); if let Some(size) = opt_size { @@ -770,86 +751,36 @@ where } } - let move_ = |place: Place<'tcx>| Operand::Move(place); - let elem_size = Place::from(self.new_temp(tcx.types.usize)); - let len = Place::from(self.new_temp(tcx.types.usize)); - - let base_block = BasicBlockData { - statements: vec![ - self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(len, Rvalue::Len(self.place)), - ], - is_cleanup: self.unwind.is_cleanup(), - terminator: Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: move_(elem_size), - targets: SwitchTargets::static_if( - 0, - self.drop_loop_pair(ety, false, len), - self.drop_loop_pair(ety, true, len), - ), - }, - }), - }; - self.elaborator.patch().new_block(base_block) + self.drop_loop_pair(ety) } /// Creates a pair of drop-loops of `place`, which drops its contents, even - /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, - /// otherwise create an index loop. - fn drop_loop_pair( - &mut self, - ety: Ty<'tcx>, - ptr_based: bool, - length: Place<'tcx>, - ) -> BasicBlock { - debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); + /// in the case of 1 panic. + fn drop_loop_pair(&mut self, ety: Ty<'tcx>) -> BasicBlock { + debug!("drop_loop_pair({:?})", ety); let tcx = self.tcx(); - let iter_ty = if ptr_based { tcx.mk_mut_ptr(ety) } else { tcx.types.usize }; + let len = self.new_temp(tcx.types.usize); + let cur = self.new_temp(tcx.types.usize); - let cur = self.new_temp(iter_ty); - let length_or_end = if ptr_based { Place::from(self.new_temp(iter_ty)) } else { length }; + let unwind = + self.unwind.map(|unwind| self.drop_loop(unwind, cur, len, ety, Unwind::InCleanup)); - let unwind = self.unwind.map(|unwind| { - self.drop_loop(unwind, cur, length_or_end, ety, Unwind::InCleanup, ptr_based) - }); + let loop_block = self.drop_loop(self.succ, cur, len, ety, unwind); - let loop_block = self.drop_loop(self.succ, cur, length_or_end, ety, unwind, ptr_based); - - let cur = Place::from(cur); - let drop_block_stmts = if ptr_based { - let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); - let tmp = Place::from(self.new_temp(tmp_ty)); - // tmp = &raw mut P; - // cur = tmp as *mut T; - // end = Offset(cur, len); - let mir_cast_kind = ty::cast::mir_cast_kind(iter_ty, tmp_ty); - vec![ - self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)), - self.assign(cur, Rvalue::Cast(mir_cast_kind, Operand::Move(tmp), iter_ty)), - self.assign( - length_or_end, - Rvalue::BinaryOp( - BinOp::Offset, - Box::new((Operand::Copy(cur), Operand::Move(length))), - ), - ), - ] - } else { - // cur = 0 (length already pushed) - let zero = self.constant_usize(0); - vec![self.assign(cur, Rvalue::Use(zero))] - }; - let drop_block = self.elaborator.patch().new_block(BasicBlockData { - statements: drop_block_stmts, + let zero = self.constant_usize(0); + let block = BasicBlockData { + statements: vec![ + self.assign(len.into(), Rvalue::Len(self.place)), + self.assign(cur.into(), Rvalue::Use(zero)), + ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Goto { target: loop_block }, }), - }); + }; + let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); self.drop_flag_test_block(reset_block, self.succ, unwind) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 3e0d53029ef..47e032758f2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -300,7 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { record_variants!( (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind), [ - Box, ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, + ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err ] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index db9d0dcc300..36324e6f8da 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -473,7 +473,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) @@ -1059,8 +1058,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&l, r_succ) } - hir::ExprKind::Box(ref e) - | hir::ExprKind::AddrOf(_, _, ref e) + hir::ExprKind::AddrOf(_, _, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | hir::ExprKind::DropTemps(ref e) @@ -1425,7 +1423,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Closure { .. } | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) => {} } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index c5b5cf7f5a9..f07a64c7c3c 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -179,8 +179,7 @@ enum ItemKind { impl<'tcx> CheckInlineAssembly<'tcx> { fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { match expr.kind { - ExprKind::Box(..) - | ExprKind::ConstBlock(..) + ExprKind::ConstBlock(..) | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ef7c68c1a33..cd676445898 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -132,7 +132,7 @@ where projection.trait_ref_and_own_substs(tcx) } else { // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys - let def_id = tcx.impl_trait_in_trait_parent(projection.def_id); + let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id); let trait_generics = tcx.generics_of(def_id); ( tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)), diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5d40c6e4e48..6e27bcc5bf3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -85,20 +85,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { Single { ref source, ref target, + ref source_bindings, + ref target_bindings, ref type_ns_only, ref nested, ref id, - // Ignore the following to avoid an infinite loop while printing. - source_bindings: _, - target_bindings: _, } => f .debug_struct("Single") .field("source", source) .field("target", target) + // Ignore the nested bindings to avoid an infinite loop while printing. + .field( + "source_bindings", + &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + ) + .field( + "target_bindings", + &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + ) .field("type_ns_only", type_ns_only) .field("nested", nested) .field("id", id) - .finish_non_exhaustive(), + .finish(), Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index eff10e5af9f..1afd8851ce0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1478,8 +1478,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { LifetimeUseSet::Many }), - LifetimeRibKind::Generics { .. } => None, - LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => { + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric => None, + LifetimeRibKind::AnonConst => { span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) } }) diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs index ab7c08958fa..0585ed76fe8 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_fuchsia.rs @@ -2,7 +2,7 @@ use crate::spec::{CodeModel, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { Target { - llvm_target: "riscv64gc-unknown-fuchsia".into(), + llvm_target: "riscv64-unknown-fuchsia".into(), pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "riscv64".into(), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 277926688e2..a9c4e126816 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -144,18 +144,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> OnUnimplementedNote { - if self.tcx.opt_rpitit_info(obligation.cause.body_id.to_def_id()).is_some() { - return OnUnimplementedNote::default(); - } - let (def_id, substs) = self .impl_similar_to(trait_ref, obligation) .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); let trait_ref = trait_ref.skip_binder(); - let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); - let mut flags = - vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))]; + let mut flags = vec![]; + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, + // but I guess we could synthesize one here. We don't see any errors that rely on + // that yet, though. + let enclosure = + if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) { + self.describe_enclosure(body_hir).map(|s| s.to_owned()) + } else { + None + }; + flags.push((sym::ItemContext, enclosure)); match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5541c085075..186bfc701bc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2944,9 +2944,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SizedYieldType => { err.note("the yield type of a generator must have a statically known size"); } - ObligationCauseCode::SizedBoxType => { - err.note("the type of a box expression must have a statically known size"); - } ObligationCauseCode::AssignmentLhsSized => { err.note("the left-hand-side of an assignment must have a statically known size"); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1aaadae12dd..23754480fcf 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -211,6 +211,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { type Error = FulfillmentErrorCode<'tcx>; type OUT = Outcome<Self::Obligation, Self::Error>; + /// Compared to `needs_process_obligation` this and its callees + /// contain some optimizations that come at the price of false negatives. + /// + /// They + /// - reduce branching by covering only the most common case + /// - take a read-only view of the unification tables which allows skipping undo_log + /// construction. + /// - bail out on value-cache misses in ena to avoid pointer chasing + /// - hoist RefCell locking out of the loop + #[inline] + fn skippable_obligations<'b>( + &'b self, + it: impl Iterator<Item = &'b Self::Obligation>, + ) -> usize { + let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged(); + + it.take_while(|o| match o.stalled_on.as_slice() { + [o] => is_unchanged(*o), + _ => false, + }) + .count() + } + /// Identifies whether a predicate obligation needs processing. /// /// This is always inlined because it has a single callsite and it is diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0f0cccea130..b8d9cff9c48 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1298,7 +1298,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( ) { let tcx = selcx.tcx(); if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); + let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); let trait_def_id = tcx.parent(trait_fn_def_id); let trait_substs = @@ -2200,7 +2200,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( let tcx = selcx.tcx(); let mut obligations = data.nested; - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); + let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id); let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) { Ok(assoc_ty) => assoc_ty, Err(guar) => return Progress::error(tcx, guar), diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a2816124538..68b1086e8e3 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -244,7 +244,7 @@ fn associated_item_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId { - let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id()); + let fn_def_id = tcx.impl_trait_in_trait_parent_fn(opaque_ty_def_id.to_def_id()); let trait_def_id = tcx.parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); @@ -289,8 +289,39 @@ fn associated_item_for_impl_trait_in_trait( InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()), ))); - // Copy generics_of of the opaque. - trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone()); + trait_assoc_ty.is_type_alias_impl_trait(false); + + // Copy generics_of of the opaque type item but the trait is the parent. + trait_assoc_ty.generics_of({ + let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id); + let opaque_ty_parent_count = opaque_ty_generics.parent_count; + let mut params = opaque_ty_generics.params.clone(); + + let parent_generics = tcx.generics_of(trait_def_id); + let parent_count = parent_generics.parent_count + parent_generics.params.len(); + + let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone(); + + for param in &mut params { + param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32 + - opaque_ty_parent_count as u32; + } + + trait_fn_params.extend(params); + params = trait_fn_params; + + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + ty::Generics { + parent: Some(trait_def_id), + parent_count, + params, + param_def_id_to_index, + has_self: false, + has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + } + }); // There are no predicates for the synthesized associated type. trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d41bf603983..9fed1e57c92 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -117,16 +117,22 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { /// See `ParamEnv` struct definition for details. fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { - // When computing the param_env of an RPITIT, copy param_env of the containing function. The - // synthesized associated type doesn't have extra predicates to assume. - if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { - return tcx.param_env(fn_def_id); - } - // Compute the bounds on Self and the type parameters. let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); + // When computing the param_env of an RPITIT, use predicates of the containing function, + // *except* for the additional assumption that the RPITIT normalizes to the trait method's + // default opaque type. This is needed to properly check the item bounds of the assoc + // type hold (`check_type_bounds`), since that method already installs a similar projection + // bound, so they will conflict. + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should + // at least be making sure that the generics in RPITITs and their parent fn don't + // get out of alignment, or else we do actually need to substitute these predicates. + if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { + predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates; + } + // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process // can yield errors if the put in illegal associated types, like @@ -160,7 +166,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } let local_did = def_id.as_local(); - let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This isn't correct for + // RPITITs in const trait fn. + let hir_id = local_did.and_then(|def_id| tcx.opt_local_def_id_to_hir_id(def_id)); // FIXME(consts): This is not exactly in line with the constness query. let constness = match hir_id { @@ -268,8 +276,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() - && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder - && self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id + && self.tcx.is_impl_trait_in_trait(alias_ty.def_id) + && self.tcx.impl_trait_in_trait_parent_fn(alias_ty.def_id) == self.fn_def_id && self.seen.insert(alias_ty.def_id) { // We have entered some binders as we've walked into the @@ -282,11 +290,24 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { re } }); + + // If we're lowering to associated item, install the opaque type which is just + // the `type_of` of the trait's associated item. If we're using the old lowering + // strategy, then just reinterpret the associated type like an opaque :^) + let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { + self + .tcx + .type_of(alias_ty.def_id) + .subst(self.tcx, alias_ty.substs) + } else { + self.tcx.mk_alias(ty::Opaque, alias_ty) + }; + self.predicates.push( ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_ty: alias_ty, - term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(), + term: default_ty.into(), }, self.bound_vars, ) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index e9cc3875f68..5469261ef56 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -87,7 +87,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] -#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] +#![warn(multiple_supertrait_upcastable)] // // Library features: #![feature(alloc_layout_extra)] @@ -195,7 +195,7 @@ #![feature(c_unwind)] #![feature(with_negative_coherence)] #![cfg_attr(test, feature(panic_update_hook))] -#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] +#![feature(multiple_supertrait_upcastable)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 571bc4bcfd1..11cb0827578 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -28,7 +28,7 @@ use crate::fmt::{Debug, Display}; #[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))] +#[allow(multiple_supertrait_upcastable)] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// @@ -489,7 +489,7 @@ impl Error for crate::char::CharTryFromError { #[stable(feature = "duration_checked_float", since = "1.66.0")] impl Error for crate::time::TryFromFloatSecsError {} -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] impl Error for crate::ffi::FromBytesUntilNulError {} #[unstable(feature = "get_many_mut", issue = "104642")] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 87f077325f8..fe8abdf7fad 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -153,10 +153,10 @@ impl Error for FromBytesWithNulError { /// This error is created by the [`CStr::from_bytes_until_nul`] method. /// #[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub struct FromBytesUntilNulError(()); -#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] impl fmt::Display for FromBytesUntilNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "data provided does not contain a nul") @@ -324,8 +324,8 @@ impl CStr { /// ``` /// #[rustc_allow_const_fn_unstable(const_slice_index)] - #[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] + #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 6d764237dc8..fcda097f01f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -267,7 +267,7 @@ extern "C" { /// family of functions. It contains a function to format the given value. At /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. -#[cfg_attr(not(bootstrap), lang = "format_argument")] +#[lang = "format_argument"] #[derive(Copy, Clone)] #[allow(missing_debug_implementations)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -280,7 +280,7 @@ pub struct ArgumentV1<'a> { /// This struct represents the unsafety of constructing an `Arguments`. /// It exists, rather than an unsafe function, in order to simplify the expansion /// of `format_args!(..)` and reduce the scope of the `unsafe` block. -#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")] +#[lang = "format_unsafe_arg"] #[allow(missing_debug_implementations)] #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -497,7 +497,7 @@ impl<'a> Arguments<'a> { /// ``` /// /// [`format()`]: ../../std/fmt/fn.format.html -#[cfg_attr(not(bootstrap), lang = "format_arguments")] +#[lang = "format_arguments"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs index 11a50951a75..6d70796f707 100644 --- a/library/core/src/fmt/rt/v1.rs +++ b/library/core/src/fmt/rt/v1.rs @@ -5,7 +5,7 @@ //! these can be statically allocated and are slightly optimized for the runtime #![allow(missing_debug_implementations)] -#[cfg_attr(not(bootstrap), lang = "format_placeholder")] +#[lang = "format_placeholder"] #[derive(Copy, Clone)] // FIXME: Rename this to Placeholder pub struct Argument { @@ -37,7 +37,7 @@ impl Argument { } /// Possible alignments that can be requested as part of a formatting directive. -#[cfg_attr(not(bootstrap), lang = "format_alignment")] +#[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { /// Indication that contents should be left-aligned. @@ -51,7 +51,7 @@ pub enum Alignment { } /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. -#[cfg_attr(not(bootstrap), lang = "format_count")] +#[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 3bdde0993b9..4e7bae7bcb0 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -834,7 +834,7 @@ mod impls { #[inline] fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) { - let newlen = data.len() * mem::size_of::<$ty>(); + let newlen = mem::size_of_val(data); let ptr = data.as_ptr() as *const u8; // SAFETY: `ptr` is valid and aligned, as this macro is only used // for numeric primitives which have no padding. The new slice only diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index ae00232c12c..de638552fa3 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -278,7 +278,7 @@ //! //! ``` //! # #![allow(unused_must_use)] -//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))] +//! # #![allow(map_unit_fn)] //! let v = vec![1, 2, 3, 4, 5]; //! v.iter().map(|x| println!("{x}")); //! ``` diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 78e27d73065..f19636fba5d 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::marker::Destruct; use crate::mem; use crate::ops::{self, Try}; @@ -20,7 +21,8 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -pub trait Step: Clone + PartialOrd + Sized { +#[const_trait] +pub trait Step: ~const Clone + ~const PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// /// Returns `None` if the number of steps would overflow `usize` @@ -234,7 +236,8 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $u_narrower { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $u_narrower { step_identical_methods!(); #[inline] @@ -266,7 +269,8 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $i_narrower { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $i_narrower { step_identical_methods!(); #[inline] @@ -330,7 +334,8 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $u_wider { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $u_wider { step_identical_methods!(); #[inline] @@ -355,7 +360,8 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - impl Step for $i_wider { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const Step for $i_wider { step_identical_methods!(); #[inline] @@ -405,7 +411,8 @@ step_integer_impls! { } #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -impl Step for char { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> Option<usize> { let start = start as u32; @@ -423,6 +430,7 @@ impl Step for char { } #[inline] + #[rustc_allow_const_fn_unstable(const_try)] fn forward_checked(start: char, count: usize) -> Option<char> { let start = start as u32; let mut res = Step::forward_checked(start, count)?; @@ -439,6 +447,7 @@ impl Step for char { } #[inline] + #[rustc_allow_const_fn_unstable(const_try)] fn backward_checked(start: char, count: usize) -> Option<char> { let start = start as u32; let mut res = Step::backward_checked(start, count)?; @@ -514,6 +523,7 @@ macro_rules! range_incl_exact_iter_impl { } /// Specialization implementations for `Range`. +#[const_trait] trait RangeIteratorImpl { type Item; @@ -528,7 +538,7 @@ trait RangeIteratorImpl { fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>; } -impl<A: Step> RangeIteratorImpl for ops::Range<A> { +impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> { type Item = A; #[inline] @@ -614,7 +624,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> { } } -impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { +impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_next(&mut self) -> Option<T> { if self.start < self.end { @@ -702,7 +712,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Step> Iterator for ops::Range<A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> { type Item = A; #[inline] @@ -812,7 +823,8 @@ range_incl_exact_iter_impl! { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Step> DoubleEndedIterator for ops::Range<A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<A> { #[inline] fn next_back(&mut self) -> Option<A> { self.spec_next_back() diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index ed23873cdde..7a10dea500a 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,3 +1,4 @@ +use crate::marker::Destruct; use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. @@ -37,6 +38,7 @@ use crate::ops::{ControlFlow, Try}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] +#[const_trait] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -131,7 +133,10 @@ pub trait DoubleEndedIterator: Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { for i in 0..n { self.next_back().ok_or(i)?; } @@ -181,6 +186,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] + #[rustc_do_not_const_check] fn nth_back(&mut self, n: usize) -> Option<Self::Item> { self.advance_back_by(n).ok()?; self.next_back() @@ -218,6 +224,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[rustc_do_not_const_check] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -289,6 +296,7 @@ pub trait DoubleEndedIterator: Iterator { #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] + #[rustc_do_not_const_check] fn rfold<B, F>(mut self, init: B, mut f: F) -> B where Self: Sized, @@ -344,6 +352,7 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] + #[rustc_do_not_const_check] fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> where Self: Sized, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index e791158e259..6fc86550b63 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,5 +1,6 @@ use crate::array; use crate::cmp::{self, Ordering}; +use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; @@ -69,7 +70,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[doc(notable_trait)] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Iterator { /// The type of the elements being iterated over. #[rustc_diagnostic_item = "IteratorItem"] @@ -336,8 +337,10 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - #[rustc_do_not_const_check] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { for i in 0..n { self.next().ok_or(i)?; } @@ -385,8 +388,10 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] - fn nth(&mut self, n: usize) -> Option<Self::Item> { + fn nth(&mut self, n: usize) -> Option<Self::Item> + where + Self::Item: ~const Destruct, + { self.advance_by(n).ok()?; self.next() } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index af02848233d..c8f60defff7 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,4 +86,5 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +#[const_trait] +pub unsafe trait TrustedStep: ~const Step {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24bad799fc8..1076d357070 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,7 +95,7 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] -#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] +#![warn(multiple_supertrait_upcastable)] // // Library features: #![feature(const_align_offset)] @@ -123,9 +123,11 @@ #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] +#![feature(const_intoiterator_identity)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] +#![feature(const_iter)] #![feature(const_likely)] #![feature(const_maybe_uninit_uninit_array)] #![feature(const_maybe_uninit_as_mut_ptr)] @@ -241,7 +243,7 @@ #![feature(unsized_fn_params)] #![feature(asm_const)] #![feature(const_transmute_copy)] -#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] +#![feature(multiple_supertrait_upcastable)] // // Target features: #![feature(arm_target_feature)] @@ -254,7 +256,6 @@ #![feature(sse4a_target_feature)] #![feature(tbm_target_feature)] #![feature(wasm_target_feature)] -#![cfg_attr(bootstrap, feature(cmpxchg16b_target_feature))] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3b026bc0e0f..529f62f4d6c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -340,9 +340,9 @@ pub macro debug_assert_matches($($arg:tt)*) { #[stable(feature = "matches_macro", since = "1.42.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")] macro_rules! matches { - ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { + ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { match $expression { - $( $pattern )|+ $( if $guard )? => true, + $pattern $(if $guard)? => true, _ => false } }; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 427146941ad..9a0fd1f5f51 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -97,7 +97,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {} #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] #[rustc_deny_explicit_impl] -#[cfg_attr(not(bootstrap), rustc_coinductive)] +#[rustc_coinductive] pub trait Sized { // Empty. } @@ -877,8 +877,7 @@ pub trait Tuple {} /// All types that have the same size and alignment as a `usize` or /// `*const ()` automatically implement this trait. #[unstable(feature = "pointer_like_trait", issue = "none")] -#[cfg_attr(bootstrap, lang = "pointer_sized")] -#[cfg_attr(not(bootstrap), lang = "pointer_like")] +#[lang = "pointer_like"] #[rustc_on_unimplemented( message = "`{Self}` needs to have the same alignment and size as a pointer", label = "`{Self}` needs to be a pointer-like type" diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 0d25ab1d5e1..2d48e271580 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -121,7 +121,7 @@ impl SocketAddr { /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { match ip { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), @@ -141,7 +141,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "ip_addr", since = "1.7.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> IpAddr { match *self { SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), @@ -182,7 +182,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { match *self { SocketAddr::V4(ref a) => a.port(), @@ -226,7 +226,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn is_ipv4(&self) -> bool { matches!(*self, SocketAddr::V4(_)) } @@ -248,7 +248,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn is_ipv6(&self) -> bool { matches!(*self, SocketAddr::V6(_)) } @@ -268,7 +268,7 @@ impl SocketAddrV4 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { ip, port } } @@ -285,7 +285,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> &Ipv4Addr { &self.ip } @@ -318,7 +318,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { self.port } @@ -359,7 +359,7 @@ impl SocketAddrV6 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { SocketAddrV6 { ip, port, flowinfo, scope_id } } @@ -376,7 +376,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn ip(&self) -> &Ipv6Addr { &self.ip } @@ -409,7 +409,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn port(&self) -> u16 { self.port } @@ -452,7 +452,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn flowinfo(&self) -> u32 { self.flowinfo } @@ -492,7 +492,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")] pub const fn scope_id(&self) -> u32 { self.scope_id } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 86aa1e4fd20..c254803fbf6 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -392,14 +392,7 @@ impl<T> NeverShortCircuit<T> { pub fn wrap_mut_2<A, B>( mut f: impl ~const FnMut(A, B) -> T, ) -> impl ~const FnMut(A, B) -> Self { - cfg_if! { - if #[cfg(bootstrap)] { - #[allow(unused_parens)] - (const move |a, b| NeverShortCircuit(f(a, b))) - } else { - const move |a, b| NeverShortCircuit(f(a, b)) - } - } + const move |a, b| NeverShortCircuit(f(a, b)) } } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index febe57dc90b..c4b89a63019 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1003,22 +1003,25 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {} #[stable(feature = "pin", since = "1.33.0")] impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {} -/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2]. +/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally. /// -/// Unlike [`Box::pin`], this does not involve a heap allocation. +/// Unlike [`Box::pin`], this does not create a new heap allocation. As explained +/// below, the element might still end up on the heap however. /// -/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this -/// effectively pins the `value` in memory, where it will be unable to be moved. -/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such -/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore, -/// moving it. -/// See [the `Unpin` section of the `pin` module][self#unpin] for more info. +/// The local pinning performed by this macro is usually dubbed "stack"-pinning. +/// Outside of `async` contexts locals do indeed get stored on the stack. In +/// `async` functions or blocks however, any locals crossing an `.await` point +/// are part of the state captured by the `Future`, and will use the storage of +/// those. That storage can either be on the heap or on the stack. Therefore, +/// local pinning is a more accurate term. /// -/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located -/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside -/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing -/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by -/// the `Generator`—, and thus will be stored wherever that one is. +/// If the type of the given value does not implement [`Unpin`], then this macro +/// pins the value in memory in a way that prevents moves. On the other hand, +/// if the type does implement [`Unpin`], <code>[Pin]<[&mut] T></code> behaves +/// like <code>[&mut] T</code>, and operations such as +/// [`mem::replace()`][crate::mem::replace] or [`mem::take()`](crate::mem::take) +/// will allow moves of the value. +/// See [the `Unpin` section of the `pin` module][self#unpin] for details. /// /// ## Examples /// @@ -1158,9 +1161,9 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {} /// /// If you really need to return a pinned value, consider using [`Box::pin`] instead. /// -/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be -/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not -/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`] +/// On the other hand, local pinning using [`pin!`] is likely to be cheaper than +/// pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not +/// requiring an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`] /// constructor. /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 123561873a6..2f6b1c74da0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1951,8 +1951,7 @@ macro_rules! if_not_8_bit { ($_:ident, $($tt:tt)*) => { $($tt)* }; } -#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))] -#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))] +#[cfg(target_has_atomic_load_store)] macro_rules! atomic_int { ($cfg_cas:meta, $cfg_align:meta, @@ -3125,8 +3124,7 @@ atomic_int_ptr_sized! { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -3168,8 +3166,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. @@ -3186,8 +3183,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_add). #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. @@ -3204,8 +3200,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_sub). #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. @@ -3221,8 +3216,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange<T: Copy>( dst: *mut T, @@ -3257,8 +3251,7 @@ unsafe fn atomic_compare_exchange<T: Copy>( } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange_weak<T: Copy>( dst: *mut T, @@ -3293,8 +3286,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` @@ -3310,8 +3302,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` @@ -3327,8 +3318,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` @@ -3344,8 +3334,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` @@ -3362,8 +3351,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (signed comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` @@ -3380,8 +3368,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (signed comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` @@ -3398,8 +3385,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (unsigned comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` @@ -3416,8 +3402,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (unsigned comparison) #[inline] -#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] -#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] +#[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` diff --git a/library/core/tests/iter/consts.rs b/library/core/tests/iter/consts.rs new file mode 100644 index 00000000000..d56687e48c9 --- /dev/null +++ b/library/core/tests/iter/consts.rs @@ -0,0 +1,36 @@ +#[test] +fn const_manual_iter() { + struct S(bool); + + impl const Iterator for S { + type Item = (); + + fn next(&mut self) -> Option<Self::Item> { + if self.0 == false { + self.0 = true; + Some(()) + } else { + None + } + } + } + const { + let mut val = S(false); + assert!(val.next().is_some()); + assert!(val.next().is_none()); + assert!(val.next().is_none()); + } +} + +#[test] +fn const_range() { + const { + let mut arr = [0; 3]; + for i in 0..arr.len() { + arr[i] = i; + } + assert!(arr[0] == 0); + assert!(arr[1] == 1); + assert!(arr[2] == 2); + } +} diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index 770b6f7601f..cbb18e79e2d 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -20,6 +20,8 @@ mod range; mod sources; mod traits; +mod consts; + use core::cell::Cell; use core::convert::TryFrom; use core::iter::*; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index ccb7be68eb1..637cc6e9f62 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -12,8 +12,11 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_for)] #![feature(const_hash)] #![feature(const_heap)] +#![feature(const_intoiterator_identity)] +#![feature(const_iter)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b2b6d86134b..4b31c552eed 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -823,8 +823,22 @@ pub trait Read { /// Read the exact number of bytes required to fill `cursor`. /// - /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to - /// allow use with uninitialized buffers. + /// This is similar to the [`read_exact`](Read::read_exact) method, except + /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use + /// with uninitialized buffers. + /// + /// # Errors + /// + /// If this function encounters an error of the kind [`ErrorKind::Interrupted`] + /// then the error is ignored and the operation will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// + /// If any other read error is encountered then this function immediately + /// returns. + /// + /// If this function returns an error, all bytes read will be appended to `cursor`. #[unstable(feature = "read_buf", issue = "78485")] fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> { while cursor.capacity() > 0 { diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs index 7cecd1bbfaa..4e88ab8ff5c 100644 --- a/library/std/src/os/android/net.rs +++ b/library/std/src/os/android/net.rs @@ -1,8 +1,8 @@ //! Android-specific networking functionality. -#![unstable(feature = "tcp_quickack", issue = "96256")] +#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 258919d53a4..99a4e0b5106 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -399,7 +399,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> { } } -#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "asfd_rc", since = "1.69.0")] impl<T: AsFd> AsFd for crate::rc::Rc<T> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 0a4cefd2095..592e072ad90 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -254,7 +254,7 @@ impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> { } } -#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "asfd_rc", since = "1.69.0")] impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> { #[inline] fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs index 94081c8dd31..fcb3bb83485 100644 --- a/library/std/src/os/linux/net.rs +++ b/library/std/src/os/linux/net.rs @@ -1,8 +1,8 @@ //! Linux-specific networking functionality. -#![unstable(feature = "tcp_quickack", issue = "96256")] +#![stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub use crate::os::net::linux_ext::addr::SocketAddrExt; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs index 85065984fbb..ea8102c9cc0 100644 --- a/library/std/src/os/net/linux_ext/addr.rs +++ b/library/std/src/os/net/linux_ext/addr.rs @@ -4,7 +4,7 @@ use crate::os::unix::net::SocketAddr; use crate::sealed::Sealed; /// Platform-specific extensions to [`SocketAddr`]. -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub trait SocketAddrExt: Sealed { /// Creates a Unix socket address in the abstract namespace. /// @@ -22,7 +22,6 @@ pub trait SocketAddrExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, SocketAddr}; /// use std::os::linux::net::SocketAddrExt; /// @@ -38,6 +37,7 @@ pub trait SocketAddrExt: Sealed { /// Ok(()) /// } /// ``` + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] fn from_abstract_name<N>(name: N) -> crate::io::Result<SocketAddr> where N: AsRef<[u8]>; @@ -47,7 +47,6 @@ pub trait SocketAddrExt: Sealed { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, SocketAddr}; /// use std::os::linux::net::SocketAddrExt; /// @@ -60,5 +59,6 @@ pub trait SocketAddrExt: Sealed { /// Ok(()) /// } /// ``` + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] fn as_abstract_name(&self) -> Option<&[u8]>; } diff --git a/library/std/src/os/net/linux_ext/mod.rs b/library/std/src/os/net/linux_ext/mod.rs index 318ebacfd7a..e7423dce613 100644 --- a/library/std/src/os/net/linux_ext/mod.rs +++ b/library/std/src/os/net/linux_ext/mod.rs @@ -2,7 +2,7 @@ #![doc(cfg(any(target_os = "linux", target_os = "android")))] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub(crate) mod addr; #[unstable(feature = "tcp_quickack", issue = "96256")] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index ece2b33bddf..52a0da5bf1a 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -245,12 +245,12 @@ impl SocketAddr { } } -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] impl Sealed for SocketAddr {} #[doc(cfg(any(target_os = "android", target_os = "linux")))] #[cfg(any(doc, target_os = "android", target_os = "linux"))] -#[unstable(feature = "unix_socket_abstract", issue = "85410")] +#[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] impl linux_ext::addr::SocketAddrExt for SocketAddr { fn as_abstract_name(&self) -> Option<&[u8]> { if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 272b4f5dcd5..e64569758a0 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -102,7 +102,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -119,7 +118,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> { unsafe { let socket = UnixDatagram::unbound()?; @@ -217,7 +216,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -235,7 +233,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { cvt(libc::connect( @@ -523,7 +521,6 @@ impl UnixDatagram { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { @@ -535,7 +532,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> { unsafe { let count = cvt(libc::sendto( diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 02090afc82f..83f0debe676 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -90,7 +90,6 @@ impl UnixListener { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener}; /// /// fn main() -> std::io::Result<()> { @@ -107,7 +106,7 @@ impl UnixListener { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index dff8f6e8567..65cb4ae07a5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -106,7 +106,6 @@ impl UnixStream { /// # Examples /// /// ```no_run - /// #![feature(unix_socket_abstract)] /// use std::os::unix::net::{UnixListener, UnixStream}; /// /// fn main() -> std::io::Result<()> { @@ -123,7 +122,7 @@ impl UnixStream { /// Ok(()) /// } /// ```` - #[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[stable(feature = "unix_socket_abstract", since = "CURRENT_RUSTC_VERSION")] pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 9fa8f5702a8..345d72ef867 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -308,8 +308,7 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> { BacktraceStyle::Short } }) - .unwrap_or(if cfg!(target_os = "fuchsia") { - // Fuchsia components default to full backtrace. + .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT { BacktraceStyle::Full } else { BacktraceStyle::Off diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index c080c176a2a..e767b2866cb 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -76,3 +76,12 @@ cfg_if::cfg_if! { pub mod c; } } + +cfg_if::cfg_if! { + // Fuchsia components default to full backtrace. + if #[cfg(target_os = "fuchsia")] { + pub const FULL_BACKTRACE_DEFAULT: bool = true; + } else { + pub const FULL_BACKTRACE_DEFAULT: bool = false; + } +} diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index d2c597664fa..373157bd9e8 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1236,7 +1236,17 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { } pub fn stat(path: &Path) -> io::Result<FileAttr> { - metadata(path, ReparsePoint::Follow) + match metadata(path, ReparsePoint::Follow) { + Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { + if let Ok(attrs) = lstat(path) { + if !attrs.file_type().is_symlink() { + return Ok(attrs); + } + } + Err(err) + } + result => result, + } } pub fn lstat(path: &Path) -> io::Result<FileAttr> { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 8b80dfc0f9b..54971af644c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -339,6 +339,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car "" }; + // `libtest` uses this to know whether or not to support + // `-Zunstable-options`. + if !builder.unstable_features() { + cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); + } + let mut features = String::new(); // Cranelift doesn't support `asm`. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 58729f396f0..0fee094c222 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1153,6 +1153,11 @@ impl Config { config.rust_profile_generate = flags.rust_profile_generate; } + // rust_info must be set before is_ci_llvm_available() is called. + let default = config.channel == "dev"; + config.ignore_git = ignore_git.unwrap_or(default); + config.rust_info = GitInfo::new(config.ignore_git, &config.src); + if let Some(llvm) = toml.llvm { match llvm.ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), @@ -1346,10 +1351,6 @@ impl Config { config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0); - let default = config.channel == "dev"; - config.ignore_git = ignore_git.unwrap_or(default); - config.rust_info = GitInfo::new(config.ignore_git, &config.src); - let download_rustc = config.download_rustc_commit.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ac3843c3344..42d895a3413 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -210,10 +210,13 @@ install!((self, builder, _config), } }; LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, { - let tarball = builder - .ensure(dist::LlvmTools { target: self.target }) - .expect("missing llvm-tools"); - install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { + install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + } else { + builder.info( + &format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target), + ); + } }; Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f5d680df113..baddc9da48d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1118,7 +1118,11 @@ impl Step for Tidy { cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); cmd.arg(&builder.out); - cmd.arg(builder.jobs().to_string()); + // Tidy is heavily IO constrained. Still respect `-j`, but use a higher limit if `jobs` hasn't been configured. + let jobs = builder.config.jobs.unwrap_or_else(|| { + 8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32 + }); + cmd.arg(jobs.to_string()); if builder.is_verbose() { cmd.arg("--verbose"); } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 5feba4e0605..04fdb15f5ac 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -54,8 +54,8 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh ENV CC=clang CXX=clang++ -# rustc-perf version from 2022-07-22 -ENV PERF_COMMIT 3c253134664fdcba862c539d37f0de18557a9a4c +# rustc-perf version from 2023-03-15 +ENV PERF_COMMIT 9dfaa35193154b690922347ee1141a06ec87a199 RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ unzip perf.zip && \ mv rustc-perf-$PERF_COMMIT rustc-perf && \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 9abfd4e9731..de0fb95efd0 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -LLVM=llvmorg-15.0.0 +LLVM=llvmorg-16.0.0-rc4 mkdir llvm-project cd llvm-project diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index fe3083dc31e..d4d80e8f77c 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -175,8 +175,8 @@ class WindowsPipeline(Pipeline): 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 version from 2023-03-15 + perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199" rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" def download_rustc_perf(): diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c3afe0d95..989e091a0d2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -426,7 +426,7 @@ fn clean_projection<'tcx>( cx: &mut DocContext<'tcx>, def_id: Option<DefId>, ) -> Type { - if cx.tcx.def_kind(ty.skip_binder().def_id) == DefKind::ImplTraitPlaceholder { + if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) { let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 27010b771d3..d526a8be081 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1502,9 +1502,9 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( tcx: TyCtxt<'tcx>, item_did: DefId, ) -> impl fmt::Display + 'a + Captures<'tcx> { - let to_print = match visibility { - None => String::new(), - Some(ty::Visibility::Public) => "pub ".to_owned(), + let to_print: Cow<'static, str> = match visibility { + None => "".into(), + Some(ty::Visibility::Public) => "pub ".into(), Some(ty::Visibility::Restricted(vis_did)) => { // FIXME(camelid): This may not work correctly if `item_did` is a module. // However, rustdoc currently never displays a module's @@ -1512,17 +1512,17 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( let parent_module = find_nearest_parent_module(tcx, item_did); if vis_did.is_crate_root() { - "pub(crate) ".to_owned() + "pub(crate) ".into() } else if parent_module == Some(vis_did) { // `pub(in foo)` where `foo` is the parent module // is the same as no visibility modifier - String::new() + "".into() } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent)) == Some(vis_did) { - "pub(super) ".to_owned() + "pub(super) ".into() } else { - format!("pub(in {}) ", tcx.def_path_str(vis_did)) + format!("pub(in {}) ", tcx.def_path_str(vis_did)).into() } } }; diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index 72c516c93eb..0281b1c47f8 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -1,12 +1,12 @@ # Style for Templates -This directory has templates in the [Tera templating language](teradoc), which is very -similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc). +This directory has templates in the [Tera templating language][teradoc], which is very +similar to [Jinja2][jinjadoc] and [Django][djangodoc] templates, and also to [Askama][askamadoc]. [teradoc]: https://tera.netlify.app/docs/#templates -[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/ -[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/ -[askamadoc]: https://docs.rs/askama/0.10.5/askama/ +[jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/ +[djangodoc]: https://docs.djangoproject.com/en/4.1/topics/templates/ +[askamadoc]: https://docs.rs/askama/latest/askama/ We want our rendered output to have as little unnecessary whitespace as possible, so that pages load quickly. To achieve that we use Tera's @@ -30,8 +30,8 @@ contents don't necessarily need a new line. Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular -we avoid [assignments in the template logic](assignments) and [Askama -macros](macros). This also may make things easier if we switch to a different +we avoid [assignments in the template logic][assignments] and [Askama +macros][macros]. This also may make things easier if we switch to a different Jinja-style template system, like Askama, in the future. [assignments]: https://djc.github.io/askama/template_syntax.html#assignments diff --git a/src/stage0.json b/src/stage0.json index 46f70b1ef4b..9250d9c2804 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -17,409 +17,409 @@ "tool is executed." ], "compiler": { - "date": "2023-01-25", + "date": "2023-03-07", "version": "beta" }, "rustfmt": { - "date": "2023-01-30", + "date": "2023-03-07", "version": "nightly" }, "checksums_sha256": { - "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.gz": "323f3c4c41892765b24201aae83a54fcaef08e47b9b2912a2680528c6ed4f8f8", - "dist/2023-01-25/cargo-beta-aarch64-apple-darwin.tar.xz": "2039157d9100ccadf4d3596f5d7b052e10ff997b59ac7619999969794fc51eae", - "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "ac3c88c99aed8d4547f8b0f857ec3538456f10223411580278eed10f6e2be30b", - "dist/2023-01-25/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "27b11ea3c67f202e61b5e7394d36bedc7f1b054ca53d68e53ccd7bacf77b4af3", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "4d6d1d47d34e8042aa978fe5a6b5b8984d6626d38731081db2d5b413d5b844f4", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "a50e473aa6b6bffd84a719aec602d4bc19f03ccb0ee5f26340eb466501cb2970", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a043def73a5c72d515c3d7dabe09022c353b047e7a4e4e13e9b17da9b30f8828", - "dist/2023-01-25/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "a63a8915409df4ae5d76d530b46cb7e83b6e6ca79790fa095d899e33773124a0", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "9c0c413187f1f1e0f1b6f1b66af0bd1b264d94f73439f6df24f476ee1c6c04fe", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "cb79e76beb989a3e4ffd1461817ad2dd0602aca3bce1a2e54cccc1bbb518a303", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "d57c5806a13b498768b53a053c7eb17e8becb19ea5fc9561a2a600dafea32056", - "dist/2023-01-25/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "33f35d8c2f5fcd5fa7928f2186a8b2417040e01462152430bae978d8d5a661cd", - "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "80ba79da61f82dc760a9dd7bfdfde29fefcab4ae94917cbf5d908332f93061d3", - "dist/2023-01-25/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a8e48c6345b0e195ea58d6237a247b0d20c8d128af1b12813430806b9a340d5b", - "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.gz": "052e2c0ff954d66e40101dc075bdd19fdb0befcbfdbc26dd94093bc4147c65cc", - "dist/2023-01-25/cargo-beta-i686-pc-windows-gnu.tar.xz": "94681fbbeb12de4b97b0a5a0206204c41b16c3de1c7c3262e1488f00b22aeb51", - "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.gz": "3c0c2205e97136ac5e13b3c89d745af24afc60e6b5adc24abf22755d8d0007a1", - "dist/2023-01-25/cargo-beta-i686-pc-windows-msvc.tar.xz": "9ccf1a81d524fbac3f859c0185421936b97ae565164c12ed32e6a39052eac695", - "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.gz": "68749447a45ada6bb6e06488e3d58ecca7939d3c77dc40c22f22d7257eae247c", - "dist/2023-01-25/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b8942c01d1b8fd1f1f399b7f63db409a30df240b5aca5cf34e3166adafb5053", - "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f8fcf5d25353dac5d2cd6ad04b20da19b2dbccd25a977e8122d85724a632392", - "dist/2023-01-25/cargo-beta-mips-unknown-linux-gnu.tar.xz": "91d0ec836e2941287ac28a753650e1b7b57364af58fdfedebe1fafea8612f1ac", - "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "171f40046f777d84fe5a4349d3565ad3485fdf075d8fbe194ca31ba2be9eeb1a", - "dist/2023-01-25/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0521be760b2a1e6cc134bbe3473dea01a6d0fbf68b05995f41a75875d489eb60", - "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "ee7c39af31d09a42c5ce1151da6dc1147b5c1aceb0ea94cb3059bac49e72ba2a", - "dist/2023-01-25/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "dc8ddfc8bd305c3f1f4d7965b8bbd8b24235ef758c38a32b3d64b5879fab25d2", - "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "4757229750f44b3d523ef7a9c778d923113a8eb8b93ad97ef5e4f23a6f1e6a21", - "dist/2023-01-25/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "36911ebbdde86d90bca90b61b1b31f6ab054ff65907ac73a22d5ae09d061c444", - "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8e4ce0a0743d301d056a1bafb4216ae96fd6cb06ca083216eaf7f3a21514e064", - "dist/2023-01-25/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "47e28a41670bbcc7a3787c68dcf72ffe42bfbc3e9f14418871ca814538f88180", - "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7bcab6e25cd8208eb220839f6adb202dcd382e4bc32fa63b83c40fba330246b9", - "dist/2023-01-25/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "650bb4d6b51ef5293164642101395fbf6d9eedcaccccc8ff3e2be032d9e60316", - "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "fc779f539835c1f3e1e7d9c1eed932568a5e731888f766202279e9240dd20e36", - "dist/2023-01-25/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "b39ab17c34560266df7dc60b6cf5626758f8b28f7142b916f1f3399342e6e0ec", - "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7b677b4a2cc59b3baebc1265f8a364879b2195905de1eb20f62b66e2fbfdbb08", - "dist/2023-01-25/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bceab89d3ae1ffd25fc155a7b3514c69e3962ce8f7727cc7e7c4b40f0c6eb3eb", - "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "d0522064a1994aa338d12f5ef68635f8804a2cb9151dd67771ae132e65560790", - "dist/2023-01-25/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "478fdff509a609e5310c54fa1e0eecbb3870a0636132dbcc71291e150c805828", - "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.gz": "cfb5bc9dcf4c85915e5c7e4a29e7f45c4e5de4a3535c75ce7c192c08511e0350", - "dist/2023-01-25/cargo-beta-x86_64-apple-darwin.tar.xz": "6b1f48ceebc916f9829f599fc815de2b8724873ce8a22ba058a2a1ac1df46295", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "60d119c084899f0a1d7661188756833118bc538d7e7298c72d1452b06e27ef62", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "801d03dfab7e8007a97d95c551b3a069e56371fe33fa4682e20fa50a8123bc20", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "269bdb128749d234e12b5795b90acc1a91bc0c338ed3be70ab2e62d476fcd055", - "dist/2023-01-25/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "88737cc19187a0752e45345eb286a5e9d500f9c71e03bb26737888fe42b350b5", - "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.gz": "146d1af37cce4b6eff9f99bb74ad33f2d91383a2b69dfdbd59ad54fc2dd44c49", - "dist/2023-01-25/cargo-beta-x86_64-unknown-freebsd.tar.xz": "9466a4417a1ea6a9ab03ea7d05f747a731ed0bf5545148a1c782c797dcff50a9", - "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.gz": "f32fcd8a18047646865afc67f92d6edda54fbe3f4e9963aba2095e23295e6ce0", - "dist/2023-01-25/cargo-beta-x86_64-unknown-illumos.tar.xz": "25431bfe87d8c944225122d21ca4823cefe72b304b10933c628d5d2df13d5f5c", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "cd67e483efd3a9cca57523cee428cd9a5555ff93b057f7fef4178a3e2fd49309", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "45d578c09399495b67ac38358e4251e3d7a20e988428a1a5a1e39387d2664da8", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "f66eb2cf2c637b4822e2c326b4a57d63eb3c0b517ddb69ff57a45001bc0a110f", - "dist/2023-01-25/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "7a0817ef29d6511d4fd9dbbdf3e9a92635f076d9b0633cb55b325cebeee4efb9", - "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.gz": "1330a1b4f975b1d96692bdc4a6392ca87e8e99982768acefc2815e386b6f4e77", - "dist/2023-01-25/cargo-beta-x86_64-unknown-netbsd.tar.xz": "919e25bd54133f4a8cbbf09218415ca7a5041298b32181fa566c5d4a8bfd8b90", - "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.gz": "3dcf5c58141e44d1c84f33f58ca4dd99edd277ef15a69fc6b94fbe7c67a27483", - "dist/2023-01-25/rust-std-beta-aarch64-apple-darwin.tar.xz": "a651af6487e2f3246075b984fffb4072338a559ff8e6c373289a6242c0ca3ea7", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "5e3d5aa50784ee63c6df03b07ac92649f76c40ac6fb49c24d97896814002697c", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "0ae7440c74cee87c25757159a5749014eecf77b2bcee7e1e71eb9249f917d725", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.gz": "a47acbecb37786773c5d80da5990298c5facad11151c9991796eedf80472b1d5", - "dist/2023-01-25/rust-std-beta-aarch64-apple-ios.tar.xz": "9168f9b1cea16a213249a1c452a59719234c145045ddc6ae1752ce4bdf02be41", - "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.gz": "54fad0afeead88e1f33eaada03b14710052c6fa0b7130dd87463d3670f1d9fb3", - "dist/2023-01-25/rust-std-beta-aarch64-linux-android.tar.xz": "5fdd761ca88de80754cf3e1221db141204f79e6c2aa57c72c0879af3b87dd0f4", - "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "27196acc8f1ab9d6843b673835927c16d6730a8daf96b1f05959884ac53232fe", - "dist/2023-01-25/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "0ea12b5fade681173aa4795399710cf5ff21d58f5f2fe54eb8d2c7516ef387b8", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "7bd0d57ba438868635726bad30fea7a52a5c429e77329bf2977805872deb1be2", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8520674b4e10a6948b25dc0c58369e921a68c48a7b961bae510ac36e5c29cfe8", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "67c5668ce3427245821e53ea976201ebc23d1cb3c1a35a0d725d935de303e8a6", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "38236c5e562995e1aadd25151513580a2a7c7828df3baec0e0cccc0f6a856c2a", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "a5453d21e3620701a957208c573d718872c3909c2c4f9e83be33e14d36677cda", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "751928d0f640e3b77e2fde9cda623c3e9b3bca7de742100fc1f48388e4d22d8d", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "5a036c4d9cbda730e6f2af8c4912506659d1e3065b4d72050cc5b18e442105ea", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "2adfb04a0700dd3503527a80eb5ee71733b0fa2dbe974650d450d4bc3b5c8b0e", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.gz": "a92fa3278a98de5ab93d1f487863453dbe60bb31158d027aaaef85adf1f62924", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-none.tar.xz": "1c0e523505aa9dbc07ec867ff8527dde29a706868bb55694d62e31924429e235", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.gz": "4adaac4b13c8d8170b59913230ac9e313ae48400b314d2ce10c138631626728e", - "dist/2023-01-25/rust-std-beta-aarch64-unknown-uefi.tar.xz": "2a2178e4e55f35ea5147f66d36450f9694416c0fbae9b776f39f405a1ab31cbb", - "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.gz": "17e4384d3a229bc452897e26400016c70912feb7e6ac2991a256829c5b391148", - "dist/2023-01-25/rust-std-beta-arm-linux-androideabi.tar.xz": "e57afb560be9a93faf5f0f852eac5cf5b16e2c05383d995a4e6a249367ee4567", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "d5a7c8f2fd9c3a1baa573b805334e5446605d2aa4589262f67e321c0590ef19e", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1e62c48781111afd20fb1e015a4f611c3a3301762fd9e64e49beeb6f2bd14c8d", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9e62d990466900818533af63479758f01f6e914d6ccb7910639c6fbbd49ae803", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e685b0f2acf33c2eb58ac1e1a526787ee9df2f0bd1a1850581cc681c41a3ef0e", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "7a02618c26f17076add562a9f8792d170fe60190d1868703936e37df3af882e4", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "d8988dd528dcc19742b703d44dff4ebcef71cec66eaae39768434d77e53557eb", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "882e8f09cf68f135a29e64d0eb50727e4ac56939c4cfbcc3d369b928be442099", - "dist/2023-01-25/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "7d9b1ebaf89cad6024f07543519dde11da15eab0e2de3df88543156e4a44c48f", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.gz": "a7e73661652b1feb9b1f50d271ebeba2938c169c8add96add8a26ded3d8468f5", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabi.tar.xz": "2a80ab44cb2f2b9769f52b6ddc5ffa4c8994092b18a7fb3125cdfaecb4e1a578", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.gz": "f70b0f86c783cc771700dc1f59c43e53b0de2d57775fef5854cd97fde4406b11", - "dist/2023-01-25/rust-std-beta-armebv7r-none-eabihf.tar.xz": "07214e7295be853fc7859481fcf94a4b20cc3bc2c022bf1783ddea56e30f92de", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "72be8b0740b14edda6656d2b5cffc69dea01f9bad7fcc9202586a901376116b2", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "42fb2607f1c7402f4d32be981cb5c0755be2e36fd0296b3b2753eecae98e5cc3", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "ae9ec6f3c3444e5b14103db8c04b95597705fe44c68c253c75383b47da4094de", - "dist/2023-01-25/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "1e0f7f1ccf9e4f6cc010a096d01f3e6056f1d4b0d319f5699dc67cad2f889d4a", - "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.gz": "6e8b70d2606902b369dfc263ee25343fa3c71c4081f03066822e9a2a260ac573", - "dist/2023-01-25/rust-std-beta-armv7-linux-androideabi.tar.xz": "e3f9052bc831ca0a9b38a3da3be846113c6ab2c4f320ecdba489f0eddfc7e47c", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "e858e836806f3641c2f1074e63ce88771cdf135bca36d7c0d3dec0d1a4c98f8e", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "becfe9addbca5bf2123d12e70007c16c036c79fb299de2ce8da067d0f21b0f74", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eef38b595752add74cf3bd29326116e33a0945115d08ced77e603c5bb46e72c0", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "77e5cf7b344e590b9a15b2c160473f7c212304f624ed9aea8c7a8fd5e0fd787c", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "2a70ffd7f8f3289e005c0f72e2c127a44f8f014628df7ac01b4b0ae2fc61a9c9", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "97e2ae0072d5ae01644eda9a0c3438e78da27bb2f78d843fd626d3db36a6090b", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "7a30075e86bbd33241120dcf078b31ca9ec1877788db2c5700f4752cd447b587", - "dist/2023-01-25/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "2c1dfbc1361f030a3a116936f3e43e2c3adae2529feffc98a76e78fdad3572d9", - "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.gz": "aafe7ae2fc49e2c4ae9e1e008700f399f397dfca05d624dac4999f6c733ae2cb", - "dist/2023-01-25/rust-std-beta-armv7a-none-eabi.tar.xz": "d4bde0e0db35cb07134f6a94eee24e4359478dec9054e8a3802440eed68f60b7", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.gz": "fe83fe1f0b051838767589ecc9c17915441a44cd77226c9be26e9a63951bce2c", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabi.tar.xz": "94eee8d1125537ebe1002c424c686c50996c03ed31d0a1275d49fd7ef0420ae1", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.gz": "6ea9fca06fdb82026505c85a7bf7ad8be01926096be63c6cf20c5625c42df7dd", - "dist/2023-01-25/rust-std-beta-armv7r-none-eabihf.tar.xz": "70459483493bbb4cb2cc4b2af0cb012c01c47afc214643a588cf894a028a0ceb", - "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "27d86df76c05de73d0ff9542d6904f03ecbd2cedd3a9d6a9cb654dcb78363514", - "dist/2023-01-25/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "24b5a81721fe20849bdf075d39a99c0e80a21178327f9fa96b21649c99486213", - "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.gz": "3740517ab4573f77d5812c9b9c04fe63eacd29e56ea7ba5c5f335ad66026bd30", - "dist/2023-01-25/rust-std-beta-i586-pc-windows-msvc.tar.xz": "6c4e780249dcf8b306f8fab3fddd232724248b2670113dfc14c7823781d669f5", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "15fc95314219ac5b38f44a4ec3568fbb4ce66d7ff7b63cdf1fb7a8b058f2933c", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "b1a5ffd05afd400760002da124a8e5c86d091db574bf1ccf255d86b2515789e8", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.gz": "ef3551edc72cb79e776c7792346352eb858f3e3f7ee1c261b47ef974e52d9a2f", - "dist/2023-01-25/rust-std-beta-i586-unknown-linux-musl.tar.xz": "0e1a8e0ababab458af0a329e14398274fa55bf0e6ce2b2a0a515e5f6d12d6f34", - "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.gz": "74a26b7fee3e0b95f4f0e065bcac58b865abd5f9abe14e42b2263bb0b87aee69", - "dist/2023-01-25/rust-std-beta-i686-linux-android.tar.xz": "c7df97d2322f5f331d349e35091ab5a61fae8dfc16781f1a74849c7c1e150293", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.gz": "396ca6747252adc4e6d41764df00418de22c22ee77823836c4fa3f1bd7cae869", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4536de17560a21d543f81f6bdb25581a3b145b792531590a6ba35464e95c6389", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.gz": "da11b2338bacffa3940497b20fbb2544c0846696925d59cf9d7cf4514dedbb81", - "dist/2023-01-25/rust-std-beta-i686-pc-windows-msvc.tar.xz": "5bd5cd665f9e3d92f26998694c12b1f0e53df8ca9ef305c4cc48dd81bbe181f8", - "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.gz": "b1553f92e0d0891717635136ad698a017c6aaab07a58183284752ff5480b37bf", - "dist/2023-01-25/rust-std-beta-i686-unknown-freebsd.tar.xz": "d6d2a550d36028e5adf62b875fccbae2f78546828de880e5bea33effca22edbd", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "3d9f9c3108d45f95ebd12c284147111155cd3714caa555548111fb6791c7ef1b", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "a4d9ee2238037d3ca5d4a9dd51c04737ecc2a12dc0be1e2996bbe46d7c1cebb9", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.gz": "9380bbf6ac2d745d1b7c3207c2cdacdd7bef0ff225e3ee5f22e46d826835b17a", - "dist/2023-01-25/rust-std-beta-i686-unknown-linux-musl.tar.xz": "517232f4e831f5305e836cc0666adef721c1b68fae80617a57bfb56405e343b9", - "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.gz": "1e6bfe0d160e3650a1a453de57f51673a6e04f9348f361fe08d2e96fa89d058c", - "dist/2023-01-25/rust-std-beta-i686-unknown-uefi.tar.xz": "f19c1458ef1386540cffca6cf7485ad22c38f0e9ee8a62e26a4e10eeeddb2a36", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "6169b653843ce79f799a99fc7f147bf8315688214dc47a64aed792f5ca274ffa", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "7f5e0f0e02c51dd88b9b819d1ae370e922eacf2523dd0ae664cbd8d79b7cdffe", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.gz": "124c50ad3ca4da2c97a5e96599762d7fad6701d0193b4a1ba3249c3a67d349ab", - "dist/2023-01-25/rust-std-beta-mips-unknown-linux-musl.tar.xz": "0a07005e369def1cbc8d49cd2904a1fd60c23771eca700e9b4abc49d2edf74a6", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "5278c6eab22d49d033595f8b98cccfcb89fa8827ef3a8ce487e78c9f74452d2b", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "206a55c0e4fb54ccfe2f372888bf42212352d56a7f1b3ba6628aec130b325573", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "f64069192d200f852e82735e239cb678fae027a7120e9d79c136aa4a3887bdb1", - "dist/2023-01-25/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "b31af554724c4582494548efda53dbef35db5cd3609104550ab2eee1bcb3f327", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8445183d07e397b5bcd0f45fbb1b58ff22dc0901d0a1a3637761929f6b0e0364", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5919f229d0ca138205def6752109056c989493c3a2a241cbd891bfdd84f8c7f0", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "c72e51c7b1a5720dd74a923fc2ce1caaff1da484c063b50f96bcf84db529326f", - "dist/2023-01-25/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "9a11cb1d587e2389531edff732c205a653e43bc62132cf697cb9fd04842558df", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "682fe8fe1e3dad08190e8c42fb2df8fc734a42df081c59d0b30f4cc9f5fcef8d", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7eee1fff997cd847aac8d6c61cad4bc572d3069dbe59ce2a06c39d6b63346d34", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0b5c68bb95668394dda1c910cf99835007271b5598d4652c7c6b974c6c0b2acd", - "dist/2023-01-25/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "411c8552901b80720a3bca0707eef475a7ad1650d34cda0b29fedfa9fc9b1852", - "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "187fef84302125e38937cf390bdf26d40ef98c6d06fd5893db8adceab3e75f04", - "dist/2023-01-25/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "83ce613db91a23549e4a1e1d5e4c24ad3ca7ddfb586b45d25e2bd85e67a19390", - "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "785bdd67b22af15637696a03b6a4a917f8195049a4bda14a88dc48e6c3101a5e", - "dist/2023-01-25/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "df034c1d2baea51f6756e1efef58db81cda5e795691c3a7175cb3b61edd8f33a", - "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "24d020c96db72a49c39dca1546a683d4d2134718dafbd74fb846dc77b30cf78e", - "dist/2023-01-25/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "a798a58bf5723f86b08a11c92f901cee246c5a0af06c4f7e08b303c7fd6c0354", - "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0c383e01f53b5bf85301c46978493e94aef2eba98a966ea283771de7829ea492", - "dist/2023-01-25/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "61040426e2eb9950a3487109977ebfe66c134f5394c95847df222ff24c61563b", - "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "ef44851d420b5ee0cc3351084c9bc645e4caba447c8dd737840315687547657d", - "dist/2023-01-25/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "5cb083baabc7f33c515f2dbdaafd49465c85888d97af68dbd2bcd08a3e70e016", - "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "96bd2d16b470e6377c9c2894b24e77d9f7b51dd54d5369dc361791153a9d1519", - "dist/2023-01-25/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "93af94b167327c431158be466ff47b3aab8a77319bf7bed8bdbdedb4633a8e67", - "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "57071d1f70a444a1b4b26b2a579e6c6324522893de60be9e97fe281e8878f276", - "dist/2023-01-25/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "a75b8cbf062d1c6fcd8b2089c83f82b75247ced44793272ec56849c4448389f9", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "195fe88c1b4b77cb12f566e27a9d3ff25ed2edf5f26be9b3b3dd0a88ac6f5e3c", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "76884a90032874b98b0f4f873818dd90befc91d2ed96945120a1ce5a6a80c4e6", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "017a6896b2b0e534c1c80f13eca4a3a570560800a117ea2d6b4ae0e6d665a969", - "dist/2023-01-25/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "ac712a5b5cf3cd2eb2ae3825e75a5d84c5a899f86a104195b200711da15e9e53", - "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "405fd311dec82db95adea38b3ec0e53454aca72bafd58f7960f8be25b50f9bc6", - "dist/2023-01-25/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0a3c8988561da39a817a3dba8115237f1c4ab6642f1925f52b7398102184ec7a", - "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "65b8a84d7355f889de036b1ce760068c2b81d73b43e5f7da29f9706ae1806a89", - "dist/2023-01-25/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1c8843868742c36a5e9f6839275b4ad2b8a45f587f18f798448a674e0b0841cd", - "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b225da38b37554abb5a7f098be013b2e5971f9f34c634661d3244dad3ef1315f", - "dist/2023-01-25/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "78018c4b996f7fd8bcaaf6073c84a3180250840263b54cc68ff6d195855b0727", - "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.gz": "468853e0d54a486aa0a25dd9fd2ab47c08e48c6aa47838c350c108738d7ca812", - "dist/2023-01-25/rust-std-beta-sparcv9-sun-solaris.tar.xz": "c59fec4162cbd9204d73f7aada19aa459e23f3ed73584203d83d52439a982382", - "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.gz": "326a3fe4191366ad170f44bfe726d80954024b1a3c7560d75da77bd16b44cafb", - "dist/2023-01-25/rust-std-beta-thumbv6m-none-eabi.tar.xz": "9c59dca2473fc377b65ce74cda0a3a064cf9fe07b1fb1eca0a4641b6de397d0a", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ba2a8bd5d55ee9eefb6f5a5bae987822bf763783ac0374b97c823cfbcced622f", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabi.tar.xz": "e8b7df90ffd190d0122d20d4c070f42273bab2da67745f831934fbc09730f34f", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "183f0945d1df7a68c45bed842991486ffee21a03313e60e89746ac4122ca348e", - "dist/2023-01-25/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "039816d5dc555e28fe45183a09a77a6357ce571111041740d0f95e89489b7cf6", - "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.gz": "22c48ee80a14149c2635eb344f74ec5765bcc5b7eb0fa1c7ad55b25c016c0934", - "dist/2023-01-25/rust-std-beta-thumbv7m-none-eabi.tar.xz": "a690f9227a3587f5dc143ab86a1ea7c83777a36b1ff18e877801c73745ff80cf", - "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "16978fed1307ce642c4c9b0acfb09d9dc532b64a72d25e2d1f3ab3afbcb673b9", - "dist/2023-01-25/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "c1cb59f61a45cb2a842d235762d244a4f4b2f078bc9cd1fe6ef5c632c665573d", - "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "7d005cc7f199344bf7ecbcb5d3a4acc8ef42cb61d18fa091fe001872a69ab4bf", - "dist/2023-01-25/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "cb567b761f1d78188538e1a5cf4f01aadd641dfec3e8c1a3e2ff2d5e7b930070", - "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "c7c83022f3772e1f7af9e8883a1082695f17956ad4b2d4b8fafeb2a8b9ec6ee7", - "dist/2023-01-25/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "392e9bdc0d84e9b9ab83f7118abd07ca39df9fb5a8482f6c9a1bb8969db2c1b5", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "97f59b364d4a3491f612217f455b1e7285691e12e73e42d4e7a074c301a973f6", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "4935afc5e64589ca8f06d3b8bda2ccb89901a60334b50c45be0b760d6f9f58a8", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "eb165b5f5924a077c563d7e8e2eef96eff9398432748070b87f4baf0d04388a3", - "dist/2023-01-25/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "9c2bf943142fb554fe2332cd7d12ebd568b8b59e06df73e45ad35da27400757e", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "bbd4bb99dbf9b8a178ae767962877bbe8dbd73175e68db654d7eb208c0f10cff", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "265ef776729a591e3867947eb23384aeaf02887a2f03f893bb21489bac1aff88", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.gz": "177edb18d11154664c510f27fc02b566c40320b5604587975b0897a70647be3d", - "dist/2023-01-25/rust-std-beta-wasm32-unknown-unknown.tar.xz": "7105e29d9a6540ec629a8844407b84624efed5e2a2642a5fc18fa8d73ad5356e", - "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.gz": "d13a3c25523c269b2515d254558af46bb35fe24d796bdd00aafcc84c63f3ac69", - "dist/2023-01-25/rust-std-beta-wasm32-wasi.tar.xz": "97ee2ec6214ffc91e46e4e590acc8dc4e69a7a935a64a0e2af31940d745e2ac1", - "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.gz": "d184abb149484d78b713cd1d0f94db958dc4ac182eed453178f669c44856c823", - "dist/2023-01-25/rust-std-beta-x86_64-apple-darwin.tar.xz": "e3c448e63d87842f42f99390d7d0ed18c13e03a226967e8f2e9ef8c764d10318", - "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.gz": "04c884f5f4c4a6d1dfb0941b62e16ec5516d42e6ecdb7b3b86f23994b8c7b295", - "dist/2023-01-25/rust-std-beta-x86_64-apple-ios.tar.xz": "6a3c0e72376a2f1654e7ac08dc5e38794a91b432450c7bf978be97ed10f1fa61", - "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "fc41a378f93c5bf1280c52d21f495924c2e76925f609356b8d27e43d0650d2ab", - "dist/2023-01-25/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "ab6bd497938262cae110bf9f39cc94f5ef1ba831db19e63b4d60c8fef7f8dc90", - "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.gz": "d990e089f838d0158fa2ba3ea08153edb48f4346e682f0fdcdfed1b37a186b2d", - "dist/2023-01-25/rust-std-beta-x86_64-linux-android.tar.xz": "0b6e71cdcef8c32e649dc209dbe9bc30a0864aba4fc85d0d615ff5c405204f6b", - "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.gz": "3cc30012778b45a27dc6c92f5cb0955461dbd1aba130c191c20a510d29bf2c00", - "dist/2023-01-25/rust-std-beta-x86_64-pc-solaris.tar.xz": "0e3f033b01d1223d9f55c86497c9625c4de36953b6c269ca622c96b2fce09afe", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "18a61cd3593bc67eeb93b615c4585e18495128cd4f50933776705c6ff5cf1616", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "8bf3998dfd69a17354dd79dea20220f405a2a116842d3813fe033cfa5a6aafdb", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "76137f8246ad53adaf26d739c91dd3bc5820697a0c1d2af0937328bb5e6536b9", - "dist/2023-01-25/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "2febd8119b376da8f2b1baf3ca63b97d11a17e1a766986ff1d6dffc522cb0081", - "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.gz": "b5769729f089ea5cd5fb5ba1995a0e18dcef21425b69b7e952d42c5bdf0253c2", - "dist/2023-01-25/rust-std-beta-x86_64-sun-solaris.tar.xz": "a8593120f87887738390e0ec9ff1d72a743a77dc17a33276e7bec7b04f45442e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "269fec46599b8839f3a81c6cc85fbca7a7e86cb661e5cbcbffb853ba674ae1cb", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "20c2d1d3e64f56f00c237ae261d5880a7fd7c6f1e2360dc7fa0039b3ea932c66", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "d64735ce43c75d7c741f9cb7754812f09e21706be8bd0931d72b09916d312844", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "f501f199bfe1120901e919a14684e57f0723b59ffb5cad79f501834a63df5570", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.gz": "a80058880e7441e2cd6bb77a7a284902d15dc21d8f0b37f2af3b3da31f07f9f4", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-illumos.tar.xz": "17d07564595b2dbc9eecc8271d3332bef81c7a57138559740c606d2181777f89", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "0e4c01e6438fc005ba7177d33cc0dba8646eb51a47da06b079ef9fc2e264f052", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "1f95934a853b0ce1f4bc50ac86b1ae74a34acbae8a64903faf6f7ba63e49051b", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "431fa66d45ff345f1fb2e279eb52ab24757ed3971f049f9a04a63b228a417f59", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6901b028b8df3d09e994387a810d3a74b873d2ff5fcf93c1d49bf7c3521a506b", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "a22d8f960e3d15886f893dd4e137becf9c84b1bb2ce500d574e5cc85f43b2b64", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1fa467a1334a1cea4af8b27f7fc186eabf3a8f26091ae29b501bec6b2564b98e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "50f2c04d4ee499959f52546af600c40b16a5627bb9adddeab819519231cf1efe", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "69084f5bf6e22d6ba232d2040bfee15b00418ab20980c716602a19134ee54bcd", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.gz": "5a8b98fce343e17fdfd2f3f9b4f810097cdf12430e02d65b3d1042e273f1ddae", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-none.tar.xz": "d5db956978faa532d822609d475599c12507e5b67ac73b9a9194afb7449b9b7d", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.gz": "3c4f69556a6ed2c64fd6274bfa17ff489b5e0c9f1f8d6884fe31c28c39e15d89", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-redox.tar.xz": "feb6456b55a38b83755b281e039941d97659947b289ac2750fd3b3588cf43fd3", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.gz": "81e795c668369a3947d4d69aeb4f823c8446b09ae18c6fdc800d54aae514f27e", - "dist/2023-01-25/rust-std-beta-x86_64-unknown-uefi.tar.xz": "5c51b99639e5f67e01fe37a868dae17da4ff11d755434b189cc4ae81453826ac", - "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.gz": "9d6277d58b9a679d47eb80d1132d590102f632d5fdb85ba54ef653b2e602c6d3", - "dist/2023-01-25/rustc-beta-aarch64-apple-darwin.tar.xz": "6a49fa544dd3bc4d657ae064863b760935977674e6c837f6a7f84dc1c9dbe95a", - "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "0536b525d92007041a4d5f4b57601bcc17e1257f44eddd1e4630fbda8b5ea2e8", - "dist/2023-01-25/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "35621c50a8e1ce5591dfdf95b4f5e17e60478309348e67f6e3bf767b57c494ba", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "feb0c0534f2f78500a25906fb6f0bd5772574fbfbd23b6abea807f074905905a", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fb269a472ef44aad092259352bb55b24dafc56459eacb7300fd7db0bbc5a96c1", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "98514e08e1a21f94028df39496e802f5b6379414dad4e7069253cd8b3f961c43", - "dist/2023-01-25/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "b01b5ef23232834174ea31bbf402fd4652769a7fac5b522ac28e53c469389b60", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "d638873a2fe3bb666174b4270a44da25a9f7f05f0a2544598556485661b51d66", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7bd32b738a280b6d42fb925b5c7cd8b4ca660285ae77cf27b0ed6eafb0b0237c", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "8ed861c6ccc085030bb0947119746df3c83b9971e7b7c0ca43a8133700f985bc", - "dist/2023-01-25/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "f4ffb8ec45475b96815eccb657d9a5f443e8067a2f7b50a18eaf80c8a9cd1944", - "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e6a809e4e255e265aa54ac730655569e93b0227037e5eebe2995e6ed13c4a2fd", - "dist/2023-01-25/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "0849a22e9d82c3cacfb39c5067106767bc40380e231842e968770b7d79dc9376", - "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.gz": "348a94bb0048a2de0764ea5ebc83a6578d1f63f4edf8d6627cd346345cb3beda", - "dist/2023-01-25/rustc-beta-i686-pc-windows-gnu.tar.xz": "02885355eefef4a901522a441c376a59521ff91889dd6e2438cfe5869360ad7f", - "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.gz": "56d6b9b2d0e8eb13a568b60f2b5284cbdb3efcbc921d6c318408c58d12c6ee11", - "dist/2023-01-25/rustc-beta-i686-pc-windows-msvc.tar.xz": "bcf405c76b2aebb76ca70595ddbe5de1faf8c34320b08cd4839db7f46dc9dc7c", - "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.gz": "6b5c11f41bdb8a7b596ac92bfe18e7a2410a7fc77fe7ca7036e72c563b9e41c0", - "dist/2023-01-25/rustc-beta-i686-unknown-linux-gnu.tar.xz": "7291ffdbce495b5d0ca017730495300a72d3341170d099b3c8abda5cb9ed190c", - "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6005076b8cd38020a02cd2720e8c67491d31f50465d62d9f5148d93feb4eb198", - "dist/2023-01-25/rustc-beta-mips-unknown-linux-gnu.tar.xz": "1b421c2addb488faefec78cdcbbaf03a9c45640f4ba6740bbb1afbece3e30ba0", - "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2d1f7463d3922238c189c5f669b8f4e80f85f389f5edca000b63ebf041fb4222", - "dist/2023-01-25/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "29dcad8e598e6b79730a53146d3d8ceb5acd0029a83216060ece931d149e9a97", - "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "c3e1527a463155bc9ed2c3eb65217c72fd067bbd316432a16a2777a444e7eb9a", - "dist/2023-01-25/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "8a031c5830bb8168c1e20426082c0783fa52310b22a28c5fbb5b1214adcf3bd5", - "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "5c1af72641cb7bf514f936def835ebccfa908434f9e26e6d3cf65756d68fe24d", - "dist/2023-01-25/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "40a95925bb98eadd7b49be71dd9fa76abf09fc16bd2d6707e3206cf7e7f9b9ce", - "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "2dfea875b3b5f3405f9df83fd5a5144b8fc93a90ba17a3ffcb437c934a9772e8", - "dist/2023-01-25/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "2c23590890472f2ed15df449a33188bbc7d3dc8755e8929861ccdfeb24ee0909", - "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "0b31cad32717c5c7a75069bfaa32fab82d0eb75190b0d34d2e09c221def5f7a5", - "dist/2023-01-25/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "939feb641d84aa98e46934c3896adee94169d8e5d8d2d97065e904aa1eac16ad", - "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d031874dccc1fc029196bc49f7713805226be2ac03a17fc38dc2f40c7f807093", - "dist/2023-01-25/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "8b6f367822b14dfd341d711c4736e00ac1fcc914a3c5214209742f2543bba880", - "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "6fb98f6c504ff7278af6f840e39d1236b7209a35a3f5dc78d281c59a2264b525", - "dist/2023-01-25/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1e5a16e7c67bad200e3f051aa959cd9123ad26e15443128ee9ce28151b28e7ba", - "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "c8bbed9a7319e601e9e53461665201f89aceca9bc72dcdd1e3206110d535c6c4", - "dist/2023-01-25/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "05af8b1637b522af7ac981d133eaf88c157a7d4ed414ce53c13bbca0667510dd", - "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.gz": "ead6472d2644ffeb7f27252e0445aa27b9cb028dc982da011069975767711249", - "dist/2023-01-25/rustc-beta-x86_64-apple-darwin.tar.xz": "3777d00c129c51b8980afc2ba1b1605f58490ec4d5203609d260e05ae5801182", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "5871e7fa9b9af9af9ccc405866774db110dc5ba8b66649c87f546139c383cea1", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "9804f9a57acfa97db3a33fa7f77f5a8ced7d6b9e5013e61aa76287dfe45d9223", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a7387c88e4a17e331d8f8800e6be0cf113242edb2b760fcff0dcd2ff97c1ca8", - "dist/2023-01-25/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "12becb176b75b9274a44ccb22a4859fb8cb52df2cf954011c7294d22dc2e8721", - "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.gz": "262df9ec15e8b14d1a2959f9d386717147af17612ae92762916e9e195ac83c7f", - "dist/2023-01-25/rustc-beta-x86_64-unknown-freebsd.tar.xz": "2647f9420cc4b2a2a94b32ef6c7d88285bb50c3b04bbd29bdc11f6e5fb8f9c4f", - "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.gz": "82875b6f60bbdea438f0da1a162c30d236fdd32124296a83510954f89dfbb20d", - "dist/2023-01-25/rustc-beta-x86_64-unknown-illumos.tar.xz": "19bd296d5c116bdb620e50b6fba3c7d5a5e978f26a8f1be1afec1c6854408d2c", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "45b8d74f203b66d25a15e59db755918d0954a3338f08236664007de2478e2438", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "c047becdba71a802c1d06b31e5c3dce8efb11a9daa299e1cd03a0f9f6b48cbf9", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "a649445f1676acafc59b4808211aa669c9fb8093cabb7007432d0ae2f6e21239", - "dist/2023-01-25/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b6ed06a8df0de6b64099fba4d1ca9478e0802dfc086308f425692ee40faa8d2a", - "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.gz": "d939bd071f42aa7657297110be68dd9d2aad840272bf881a1fdc82053914f970", - "dist/2023-01-25/rustc-beta-x86_64-unknown-netbsd.tar.xz": "5671084575291d8c4ef2ed0930b22815d6810e2378fb98ca5a0738faa76b525b", - "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.gz": "f634a282a8388aff57d988616f17f2c511253a02d45193b03fa87167448a8cd9", - "dist/2023-01-30/rustc-nightly-aarch64-apple-darwin.tar.xz": "4fd6a4ec8665ba71ccf3ac7d08f9010b4e130ce496bc62548d36170786f213ab", - "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "5b7fc325745b2f1e22b1a58ead8163314c3ec06f4a30483bf7ddfb57f811a2d4", - "dist/2023-01-30/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "4aa8d587ebd53bbd11c33f263991328576977d801d5b6eccf56147301ea0f52e", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "7838bf7da92539b0329be0b9b80f0738df3617e982f539326a6a99892eb905f1", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "636af094f94de9baa3edd5f9e1b7655e0bb7f6f23d24d6f389a3abeab7360e00", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "51b8a8a06244ee37d2c37e84154ff87132b4f90a1e62a8c9454ed5ea5c296c1f", - "dist/2023-01-30/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "cc18ce5f4f461a830c725ca8ddccda17bd726374198c487810eab8d36a8f7c98", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "e2d7b96bf5e2feb47019c63067dbb1627bf26ac4e730774d29ea9f6967edae3a", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "0483f07f1a53949c2f04e2766f53fe9138ce126059f650ac61215e6a84c5fd57", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "d3ad417041c432438f1ed56a2324ab412dca7631a74da03e0bc72cd28e69f197", - "dist/2023-01-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "f029fafa0635efec9065d76780f003e2c4220c7b6ea4b426ebcb57d943403998", - "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "dd2ee13ccea00c23ca2f90872c7c31a3a1ef008962db9cf8066acc130bca778f", - "dist/2023-01-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "dc23fa4c0268a7227e0f9e4941376ffc4c64c0614622f442da10dbb75e014dd4", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.gz": "d4b02e59373fe60ba06e979f784bf1b8c94ca4a5ee471ed83814623db9e14af6", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-gnu.tar.xz": "5355e1bfdddd2a56dd0c882fc492e4d571e5b29636d381e848102e996ca9b680", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.gz": "02a43fb72394837461770c1b472afb534ac03bac9cf23bfdbba8227cf879dabe", - "dist/2023-01-30/rustc-nightly-i686-pc-windows-msvc.tar.xz": "78cbe74bd0f7029b01e3aeb451ea6bbc1656db1fb4a80caac4cc27b6e0144b79", - "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7fa9a3e3d70a6c15bfd00a0b5a83d73f4e952862b8ef1d6837d3598c4cee8752", - "dist/2023-01-30/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "76b3abe5c532785ab80804461204280e6d853773c62956f283f5dc88130e310c", - "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "2aa78ea99fceb90e568f6c46881623f5088afeaf47ba204abf2ef755397e84eb", - "dist/2023-01-30/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "6abe1f28662aca904b1fd91e46e0441ba7b4f66f1e7757cab93a0d73012b36fc", - "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "3afadbbe1b073ee2a81609c87c3d88a5d7344765b970b8c48dcdfe539c5ba540", - "dist/2023-01-30/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f1eb22696c376dfea266090320e7a941986f8de2176b6ceb6dc0f0452994ae4a", - "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "c7f548350e118d4281a8a6ac8044c19eb1583683490b0ea6fb9f5f27f5e3873a", - "dist/2023-01-30/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "aad40926a20ac8bda9e534d63e180adfa355e9df22a1068310cf9ae667ffd0ad", - "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "4778f49dceea661baaf641531946dda47d8ddb7f801cc63afbec37a86d45a0f4", - "dist/2023-01-30/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "1ba09bcefaf5ed5a3029230ebc3e9cad33626b38553451b952ef215c68a98e34", - "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "6efe1f619ad49c94b3e6fef2a51893cec88ecacf31d963576e6343e8a050d20d", - "dist/2023-01-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "971fdc824861c98bf223fb2c733e780cf87c90f3a5646561f4e35fa8cd068c7c", - "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "10741ef62e00541a85747db16f830c71ffa1dce036a95bc43df433e450f96602", - "dist/2023-01-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b8bc80ee97c54e428c51f56e30cdd610fb07f41bead0409b089fe56237bb0421", - "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f8f52abf57943895d34ffe2157f863bbdabaf804969baa2624e38a13648d43de", - "dist/2023-01-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7dfb9af100df05b558c873b5440c532d28de44fbf8c7d933c29481eef6693539", - "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "9454d78432ce8ad61f8cfbe448654d8acddda9c596c36c7863631c638aba949f", - "dist/2023-01-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "c69f1b0062aaf566d6610e6b19335ed002a281aa65b34c1be001a875b85f76d2", - "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "92184254f00348bfaa7f40f8a07b585eeb6dabc02e4dff3351cb395b354a930a", - "dist/2023-01-30/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "b41eff99cf9b9851ffbf496ba6dc892d5dfd124da68c91db66d6fb77b19370d4", - "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.gz": "8d901d7c2ed293a9e2d2fb8849edee50e6f6e3c5a049fa91cfb13f8f16571b7e", - "dist/2023-01-30/rustc-nightly-x86_64-apple-darwin.tar.xz": "d472dc97f3242d243f584efe113f23e62ac1f53677fb3b3cd1749adb65a6635c", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "9259adfb75f90cd43c99f253aaf4b242afe941c4075eabc6bce824c3337b4d2e", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "e42b3e9a462004296e53ed3e71403caff98b3718ff15508d913e0a25ad02ea3d", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "82f615142be1fed6ffd5c9a6f2d1d3fb73ebf32801348cf6279991c0a76b771c", - "dist/2023-01-30/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "2a4e2aad343062379334ee1a73b657656e0c03f0490c901806c864ea8a38ebe1", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "2a8fa3a6a104bd35de9a83d98786e7acb7614e0b830336adda30e8d1f1cade69", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "37327a8b756918c25cb799f2e5742a07145e4c1e424442a5d975e99aff1f303d", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.gz": "8be0295e8b89b6e8f465b0825b0625232c7624cb897efe3e0bf4da222799349c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-illumos.tar.xz": "8e515082490a64d83771131f4fa5fba8b021d205b56149459e2f2da7584407e3", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "c105e3dabdc7bebebadc6ffa5b6f3f962057948cdac6647cd5adf16d66982701", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "09b82ca24ff847e000aed1b2eaca74cdf0f6e533bd6655eaa302281eb7037163", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "e77d81b158b53a94065cd90f68e26dd12d156084b02c53c51172e02c4db58c1c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "613c7eab1b998aec0673e1781e3ed78c4d038b449d879c11254b1b6d4345e34c", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "ac8c53be048049118af9fd9d356dcc69ddfaafcd52020ea93703c94d6167b367", - "dist/2023-01-30/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "28b1c8adfffa7863bcd8a46ef407044d06fc16b29f7b6f42072fcbfbdc779e79", - "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "f7e585d9016a012e2cde4d7e0899e52e1c410c53ed9caf6db22d13f6791ffb0f", - "dist/2023-01-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "bdea28e1700f34dc0a6e57db5f73caf6c8d1671a8356cc51096f8155f58690c8", - "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9988193283871e678a0d0e08cfb5bdab37d43cb0bec0e5f63a12a38c164936b", - "dist/2023-01-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "30d1bad2b730589f9d75ca3e2d410d0f9c90707526ed6a66edac92a19eb3716c", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "7c6c93fa25193360e28a90269439b28465b6693b6ce68ff2eb1c4209c36a9d60", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "4c8331d14ab428b922135690b433f97acd37291e1801635252ab5da849d42180", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "0fb5372bf4cc0b6388194021dc7b6a539bd413e89058c05cdc42c1dfe8d92edc", - "dist/2023-01-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "0e2452ff037698781157c30c5fd67f552e897feb1d86b7b074c195c70a6a1a3a", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "6c079c2dde918cf2d9f029dfb3a2a9bebba2504dfe97c5fdc0ef79022415b9f0", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "5ab6fa16d7aaca7e6e36caea8e11b916c089dccb511f79b7f69bba667edabc50", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "7b919c9132269fcde24559af58d3d2fee56d93308d731d891f89dcee193bbbdb", - "dist/2023-01-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "53d7c7d03b64526e013c11c49519a63f51562f9682039479c377c92529e5e026", - "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "c19265cc3a85cd296a85b450e2f4e4b5f3646aa70d6c70dfdfe9ef222fd72136", - "dist/2023-01-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "66159d87fd85a4534104da3f7f5c0a14403960ff2c836eb72e35bed6a1ebde32", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "be84f8558d15dcc802f399f44f0de58e93b28e99cf62e38c0d6e6078a8d73102", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "b4e8f18335aa3cba092df29c3aadef79c0b88e00f563604467cb2485e10cced6", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "43ce7581f50e05c775b39a6a6d297d6e8c56a40f5a5817ae4d996d319fbe96c1", - "dist/2023-01-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "2ca2b20996f1a4cbdb619393a3f544ada208caaf381748ee997a70139e52a591", - "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "229fb281ec100e68445b5a402a3d39a0947475054c4f043d55ab2e33bd3d2a57", - "dist/2023-01-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "65326115afcf1c8e07cfcb9ed294a1e5a136b998557cd60b4cb976520f84cfe1", - "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "337bdf61237c8e47909c3f14b5c8fdf3b8b14f2b265e6da45cd6b4d8180d0afd", - "dist/2023-01-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "d683349af8320d6bc9f16021fc8937920d70e99cf668ce64cad962705dd20ea5", - "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "08a1ae9e61ef097c5d5ce83e5d2bdda62e72d07b4dd21aad286413c619fefa1a", - "dist/2023-01-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "cc3f1f86997c5ccf5607c8f873c916d1158da76ff971d75e36ed8e3a87c86924", - "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "f4b7084fc67cf17b3cf1d36136aa03aa5b6af188d311684b15395f05104181f6", - "dist/2023-01-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2ab645d5117606f2c7e8decbeae1d8855ec7ba53051144ba4783efee2c58d91d", - "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "cfa8baa60cc59ac2750f799d33b06eb399d330f318783907717a9e360fd7d85f", - "dist/2023-01-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bf24570425c064aaef31788bbabd6c4938c9323eca2dedf2ac9084d125623544", - "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "f5437d81735fa67ef24c7b561d1c720395f5d8d4ddcfd88364717a7ed9b96a7d", - "dist/2023-01-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "8e19c3c95d6445e1ef9b1735191f0d0bc33802bcfa138a9d676d9b266adab17c", - "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7fd91c2ef7e26c08854c91969d167d1c97538d7678c6ed7914eb0f67290d8d5d", - "dist/2023-01-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "9e8ada358580b396054278972d532ce2044550071036e9da2eab598e2953a03a", - "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "eec8b1c24ccaea22eed7708e61bd32bac0850d0dff2b06f1a15a95ab86385363", - "dist/2023-01-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "215f1f3bdd8f347af5969c66ff7f7cbf39753ae483e75e689ac581f9d35a64df", - "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "39460814c429b6a57ce72fafa583d04190053f2c2ce995c8bcb0799ecb7f8bd5", - "dist/2023-01-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6bd08db8702f2fcd9f4cd19a1d977962c84856f748552a96b564e5a77cf2fdfc", - "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "81d6335fa1265cdf99682503cfb236b914fa17d45f967e456ddbeb12bae2dcbf", - "dist/2023-01-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "d36b7517efac2c4a34a1055411f779c386c7a566e4eec408dbc8a319f67f5451", - "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "1a34ec058cb45189c4062ad2a00ab33387a54716f75005d9959cf0691d06ae50", - "dist/2023-01-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "a2fdcb7cc9fe7819699f511d52da0e8ed4e55ba42c63e7b1d61512e4e14e5c29", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "95e3f080394d2e4f9916f17c9cf5137d032da847d9ac1c04519b31177fb1618e", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c306895982f92c24559b18f8ff9e011e8722c3310e5f70010fd04b0d044c49bb", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "36331cd76f8e918b73ebf6d9095efd0a07cc9f084f194f74c881c14fbc6e8a77", - "dist/2023-01-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "2e7caa7209e52a9df17254b17f1930afd5ae973826ce3293f29b8b878aa13042", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "dec92f2c27f785f8ae0db18c2e8a9db87e1ae8addb4302f5cbe9f745cd92c4f2", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a8fef2e56d9d2be9072c17d75e7ac695eb8fc266fc35e1055fbb25757e6db29d", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "9b5f93f00f61def125436332e4b709bdfe74c441995bae49c0d482f24bd9f8f1", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "4f82313dce2e1315bd0d3ebf95f33bbdf7275c59205b0910bbc92d41c47c7c22", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "69efa04956d9bcf177a3bd9ba9541fa681b39416a1b7dd2b18415b72311897b9", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "0c3c33d744ec05e96298d0bdb9890654ab9ce3e9013b9af14c78683560456820", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "cba8b1f086c544d79aa09ac954374f44d5e7d38ad9bbc2f9e84723d0088592e5", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "ce73d1d03b62931d6eb9508b701e9dacc08b98b484af3daa79ae600c4883a9f4", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "87e1018a3ee4f781b3c1b471fcdf80ebd70096ed58b29db00ad97573626294f4", - "dist/2023-01-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "c6896ee319403ebb5c909b13feabc7411e3aa80523ef1bc84c8aae181514c923" + "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.gz": "ec2466b2212a7453ae902b85f7b1879fa9d37275f21972aef488e8b4ca04e195", + "dist/2023-03-07/cargo-beta-aarch64-apple-darwin.tar.xz": "5eaa63f70f842836dc847059ec188d5c1dbcdaf77116dc08ba6421eb09706c12", + "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "5514aa4051d8c6ff9b7e334a4cbc8b2ad5ad8db0b9853a693ae998888df0070d", + "dist/2023-03-07/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "47b4cdc96afb1796e8ddbf4fed4868d08bfc8fe90c5f517f7c4d8539d89ca827", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "514ed7e95642daaff551b31af9f6b8e1afd301d4a3197574c4296dd938f7f98d", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "0a3f61fc865330e5a9e1f37a59226a6660995ccae8610e742c2ea42a7b8f9b9f", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "838c7a9cfdf76e3e2a0e9c2ad37124eb029ea2f0e015640c7c9ca5f45fe1c260", + "dist/2023-03-07/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "1ee5a28da6b8f7fc5f98b8214ed2dda28769dc345c9ffc8046ef644f69fd0382", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "3ac81e710ff821e206148d998654044d0b3092d929da3a1d3a5ffa2ada00d922", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "64891e59a7e8c94011f98849d37a056535966966f753b923ffcf8ceccacfaf03", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "fcab9d5fddbe72db02964adf9fcc13e5acc67f0f65bcdd3bc325aa9f0c223acd", + "dist/2023-03-07/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "2bfaf117eb512e53c4f01765d198b3647fc0058d7f77721b58cfab5e72b1f7ec", + "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "dd955a4f258603e5cb5c85473fb6bfeace54cbc2345d99dc9d8fa7f984bcd915", + "dist/2023-03-07/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7b19dbf54ff04009209d505a97bf66327a87ad6ac8a9be4aa26be3d38fec52db", + "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.gz": "88e8e79c154a34596740b85030c16a27d62defef5db8eefad0b3d4397e7222af", + "dist/2023-03-07/cargo-beta-i686-pc-windows-gnu.tar.xz": "a996fac21b8198632a3bb3746549f6a36bd7c2b12d9820b7af64a5ffe8074df5", + "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.gz": "3b8834bf152ecf2bda797475d7d556746e2a1374c61e4ab2ff81b41bbff3a87f", + "dist/2023-03-07/cargo-beta-i686-pc-windows-msvc.tar.xz": "2fee05bf93a16004f4f8fde437918a44874a9495c1e45d954a1098c104249bd2", + "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.gz": "544ce4096e455c5259c4577feddaf5a6ec34e6a8bec2710e74f8910f60c1da1a", + "dist/2023-03-07/cargo-beta-i686-unknown-linux-gnu.tar.xz": "2f39706fa21cb08d8bfe6a32a5a3314742ddf040bb42e844d5b3f8d0d29fd39f", + "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.gz": "7f60d7a0d60e06fb4530291f1e64956cfc7c92bd034b63d1ebdedbeb9f7bca17", + "dist/2023-03-07/cargo-beta-mips-unknown-linux-gnu.tar.xz": "3c6d8de9f254edd01461235f14e89c7b863da84f338e3a842921dc092db4d82a", + "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2c0ef292ecd4bf27e74323ae5fa7bd6c6395d70f4adc4e6d4228c266fb87be7d", + "dist/2023-03-07/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1886d8e978dddefff73f758e7c1d28964209dc986195cd39bd8d3d34197cde52", + "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "125a9a8a6d57f1694ed5bef51d9d351da3bbf0ff1ac631641cc5046098385536", + "dist/2023-03-07/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "851654268ac5ce9d1f3dae9228464bef01771244945653ff7e9f8d7a52761813", + "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "46a3bd35af46f6b59b610bbc596233bb428c2b8387f95d3e308565d57e6ca276", + "dist/2023-03-07/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "d941bb502be268962400e78005b30ac4a5975ab012e2cb7fb631b002a7e116ec", + "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "3853bfc5c0734f3f92e0d7cd07583729d3e67f7ec3b496b5349ac690ee3632e5", + "dist/2023-03-07/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "17a0c76f33244ca66c942cd6054e343a395d27437d69f166471f0aee8c404a55", + "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "b37f9c476ae9fe802bdb0fc449657c90a567033f4df382befeee1517f53db05a", + "dist/2023-03-07/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "b315d765b176f90a5c74c102687ea8b54ea94d5a772ad03741aa3297a5466562", + "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "e84ef7a7b4fb7b504e6a0ae335432430ad9f4db356650c738e0db676ce672321", + "dist/2023-03-07/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3b830e1077a195e2048b621a1ace2c0470135ae5821f83113a16bdd449dc9828", + "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "db373e61134b7f9340b5d8dfa24fb989e3acadb90b4d27008c08715720cfeba5", + "dist/2023-03-07/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bb7d046253f1fcf98f8ef9b33820793579a09d201ae1bb5616302bcf7103453f", + "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "495c5d11852010647d15d54352052ca932034d77f3ac3bd9bf605d52c37fb47a", + "dist/2023-03-07/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "002d9a037a9de13d0e99f695bbb8f9177e14df2e6309917a7d728023dcaa1640", + "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.gz": "9c93e76966a317d2dbb673345c33269b67d6db101114275424a50f5e4c3b7a89", + "dist/2023-03-07/cargo-beta-x86_64-apple-darwin.tar.xz": "0ac70e1699e2684fcaff30d4330d04795f3f9579226dc1dd0ecefaed9efa24de", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "8ad0af38dac9c0a49d73691d7f62487c8c72a378ff4fbb7f380fd106600ce836", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "e1c263909d66c14d5b835d2d8ba9df9d1f54750a85b79c4163483126594f71fc", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "684b44e6cb7b2ea6feb8a5f768f138b7c3c3819ba5f146461ffa860e4ba2ee0d", + "dist/2023-03-07/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "194037a4e7a035becdf8540532625e7a3d2e5e9a75c093713467d16f2c630fda", + "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.gz": "b19ed2a67bc6d654520c2ceda0d1a8e0128a0d042a72cb6506eaf975c3665bc1", + "dist/2023-03-07/cargo-beta-x86_64-unknown-freebsd.tar.xz": "2773155eb716d1cde85c8ee7fe87f534decf08cb92d4812463a8f5f45b5cf4b9", + "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.gz": "3d97d07c075c7473645b71391fdecb6b8a43af42f15ccce0bc13146624f3d9e7", + "dist/2023-03-07/cargo-beta-x86_64-unknown-illumos.tar.xz": "6266332b1a18e851cd4cf618c1ba5a8162c06c8ceffa3a6e619cbfaf5c8f2914", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "6e0ca0e10d1243e81768f1760f268aa2ce1dcf4f79a718a44e09b92ae5b2c87a", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "84aa0a73dd6d3ab9d5efb10e0480dedb864341124c19b35040239af27fcd8651", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "6de4590228b94c6c62fec90da7f5579fef16cddd30d4bad29ac39e40081818be", + "dist/2023-03-07/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "317b64417648885b08064543e0dea13d1062e682224b3b866c12ac6abeda1648", + "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.gz": "aad64656cc4b9915bfe5ac780ac935964a13481a9070ca31f58d5b8c1750e40b", + "dist/2023-03-07/cargo-beta-x86_64-unknown-netbsd.tar.xz": "0ba3f47a551b38c83106003c775539b7384c9bbfa4cae28923e63e28a32227da", + "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.gz": "b3f00164840826f89eb930445cac0afa2ebda2153195574b91ff4dcd286042c1", + "dist/2023-03-07/rust-std-beta-aarch64-apple-darwin.tar.xz": "c94d3fe8dfaf35f88d557a37e3aa1da8999b5e2e022f85f1bc0ae7ed5218a3ef", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3f43a002c0c099eedf12c2d2d3e1bee3c8ea345368e89cedd5918705f37086d5", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "891547f5c2d06ef95f272f829438b0d5c9f34d9e1e7d068dbb0a5d31c685658c", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.gz": "c1fe0f8fb661dec65dd7a13b038deae93d4b66f0e0988a0a72374e9945915612", + "dist/2023-03-07/rust-std-beta-aarch64-apple-ios.tar.xz": "1f65f0ae9685aaf14805b63111ddae27c8e9b39cc88cb3a5347ad9e93d863581", + "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.gz": "9fc988f57fb6a0530a338cd3a0a87925b095e9a2f3887f87231c9414828241c5", + "dist/2023-03-07/rust-std-beta-aarch64-linux-android.tar.xz": "2aab2cc1377391588db019a231d8f989de79342a630625a4e7c2fee560549668", + "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4527b7439a0419e96b8c59735fbe98d8628985b63ce64c24749273b625012c39", + "dist/2023-03-07/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "80badae3069223541e3092b07331eab3330bd66a21522037fece15314085c513", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "6f7141d28b549d6cf6f64a5944a4748db730d865a9bb1f3a344cd19cd45269d1", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "87f97fad69b53a36354c17abfa58edbaaf86d1db071a53fa96e9822c4f0a7846", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "8decda618f8cf30f51b8f26861baab0f53824af6cfa965af585f0653771d113a", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "dd140223ec842ebe4c69ec6aa2966b97dacdd9ce112490e310f374134188d0c4", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4aa6ad6fbfb9bea40c5b4c3fdae8f79feeaeca71f0848c1e9281650d4b5880e5", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "2d62f25f3c16704f2f52b8bf2fb505b5f8e3a3e44ae3971b0a3081fdd5932bc3", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "87982e6e6e3865d520fa35994948c7b82c4fc9f698b4e1316e0ab0bbff3d7455", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "815a45384be320225b438be952d798ddcbfc223d7629ce8e106499f626c170f7", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.gz": "041d4a16c7e6ea18f76b119e069630636716c5f7c2f38e0fdfe69062da9cd942", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-none.tar.xz": "227e8434ac0f294bdb102d4aad6c6b1425f148f2bf8eac9473f522e4e8851d15", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.gz": "a1f6c1268c3e28e78f43f2a922ff2d260466f4e2888555c122fb490ba28d8f53", + "dist/2023-03-07/rust-std-beta-aarch64-unknown-uefi.tar.xz": "68f46477d721677d2faf0091aad1d2f72387bdf1e5590dead06eec51390e9906", + "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.gz": "d1bdca54a9807d058a26f2999fc82ae474e6d5f8cb555196f6583130c81bd6ee", + "dist/2023-03-07/rust-std-beta-arm-linux-androideabi.tar.xz": "8cc49d1e16181848d73d617914d664b45cc42fc8bf80d3bca7ca69fe1a4fe7ee", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "b09c3776268888966d3752dc614e677c821731593ef757ce45fcd6f6b1b28bdf", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "7d43314c408514ece5f3ab6929f906bb224336171c3fe41a5b980afedfbeb172", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "9493fb7c2cf30e0c986babd8ec41e3c626373d4e62f8558dacd01cfb85dec04a", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "9c833f219410f9e6e77451e4af1a355685831dbeaa99006ac814801883a17312", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8e9c3045dbf1fba7e54b8d34bbc3ed8a95b6c984ebee0123690889455d963f87", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "54f7f9a2baf29a5fbc41b6624a4ae0f056e10f0dbfffffcd08377dc6888ca85f", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "3f214ab1da499c6a64bc5bc54fb9e95becb318b469531e4d9f7b234f5456dcff", + "dist/2023-03-07/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "3e4c0742356393a07cbcc6502e1d1f9a3187921c67d4d554bc3c95bb9e4e226f", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.gz": "25f7466a419353fd7e4c9a3771df8f0a64e689d3c38f18e297a6a2c670174d9b", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabi.tar.xz": "42c713261708e90fcab6dd2b8d5b2df4387a33c829bc981f502622d5ca352ac4", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.gz": "31b240296f2e72dbeb3facf395486e8f8ac0b0b5f10a389ed4e6dd803821afac", + "dist/2023-03-07/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c33a7bb47b94f8d5c716e4d6b43bf17395bbe9611762a01a5763dda4e725c64d", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "509cdcdc107051d7cbc8f02874445a9cb2f0dcd3190cfabd68615b8883b8f32e", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "01fb58ffd2cb6257f25d290cbd25be8bf216c18ccbfd97a42317d9e442008d4c", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "19ada8a7b1178056008f3168dd854994d6dc0fd32facebef915891b5a7fe83ae", + "dist/2023-03-07/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "5925328b29a9a54536ea7de55442f4bcacce4b2ec01c69e7c8d5e7f109f5dcab", + "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.gz": "bd569b576ad68f20d0352e5ae9a7ea0008941f879dcf1cd57f14b7eb7fddb95f", + "dist/2023-03-07/rust-std-beta-armv7-linux-androideabi.tar.xz": "c483223f7abed0c145b9c94a6630a1d4caf26720cd451cb4b70971f1f907d6cc", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "84a1ea166b81fe2cc673beac5831ee182a303c5166279af33478a730a1987086", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "fa04a59350792a59c8b62800002f5f6e013710d96e3e9d3a6787b1c3b668569c", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a605160aeef9a5d60bb83376d816112c621f753e4f16907481aeeea27568da77", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d6f3e091217d657a259f7392acf26aa7cc2a7692028412bb97cd26cb7f31b34a", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "ce179ad977098491c2dd27d57d7dc5a71b9b450b07d36c19e55c0cf9961d3888", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "fdfa1b894ef5d1afe7cf9790de3077632d4fe693464d19ede5d6b377ff09a73d", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "673dae7f6d71cf984b69e0bf22b8f50a8597d5c6304ac0fc613ad5116c4a8fa7", + "dist/2023-03-07/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "9bd8bd07be4488f6828ce4b5456bcfe49bd9ae416cbb859c9b1460334ac9f4fa", + "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.gz": "b571a28b02107adc227fe02878064f44e5d23bcc91b530f57b4dfa43a4c3ec1c", + "dist/2023-03-07/rust-std-beta-armv7a-none-eabi.tar.xz": "854433b082a6bad442c1b9cc9708357b779cbcb84de65f832cfcba06a6088157", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.gz": "04c1479778038948f30d2fa87a18562939569422fe57e91659f9f0a5e8ca7f5a", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabi.tar.xz": "38d52dc26074ebd93e6a61dbb0c934a66f32dd1113cdd9d32e4d5829ce62e188", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.gz": "14e4707dc514aec378e1aae2949231ee3bbe216164a794e7e6d233db54f13459", + "dist/2023-03-07/rust-std-beta-armv7r-none-eabihf.tar.xz": "c0bf08f5d378955ba15441b5229d1ef202e6d071a243ae7fb34b9f1724fd90cf", + "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "d9468e5a056478482cb9a85a63aba6d1987026275ed0c8ef64fe7a84ee5e35f6", + "dist/2023-03-07/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "77262a746f577b0e6f9b6c1aa338f90eeaf8221ad70f5ca93500459c1749f3b3", + "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2c8c95b80e43acb921674d4a9b2986d89dc008e5977a6a05e820adfd385f55ca", + "dist/2023-03-07/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9573dbb30fd7a24d4d7e831f51e6c05c76d856d545ce4601f4e91b784c348355", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "f1861d5b7875a81a11a98a6cde90fe958d1819517de21e377cd05b58eb5dde27", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "f8e816f9ca02c3cc515d07d5b5cecc8c5dcee64b8deb1bc1ab249010664d1cef", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.gz": "614a80336890ab422366caf16c73c26a7982c2369393a40633eb925113e93306", + "dist/2023-03-07/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e8dbf05a3964ce39dc4c732c5a4bce60cea1764c151b1ed4333e0da858659050", + "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.gz": "34df9ba98cbb7fef8624e921045110d0b4623028a611f5819bc79aef9e611024", + "dist/2023-03-07/rust-std-beta-i686-linux-android.tar.xz": "bef0d789d8d66d0eb69970ee23e4cc966f655efde901db13a4fc9d02c875848f", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c86ba5a55d449af72a4450566a9152edac5fb43ab03d1385779bb4ab62255f7e", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-gnu.tar.xz": "8dfab1eb07c9391be73cdefd892f6d7ca72be99a7fda5528906343108c5b5503", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.gz": "99c56608131dbab4775a35ea16d50149af37ea57ef0c0dd52bec2639dc3bfce6", + "dist/2023-03-07/rust-std-beta-i686-pc-windows-msvc.tar.xz": "1983fae15ae3e5480efb1cbd0fd0509e863eecdc456e50899bdc6cfc2da580c1", + "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.gz": "4652d56693b3432446ebeb5b52399b27d95066c0085a24a4ff5b96a2116cef95", + "dist/2023-03-07/rust-std-beta-i686-unknown-freebsd.tar.xz": "a89a970a699864eda563170f41210ae3692059f8b141d532172907ca1456e8a4", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "0d6b69445aa064ad6c53a26b52011b4533e83c7398a9ff4a10c29bd2c5f1673a", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4cd1770586a92192da3aa4fa8a846412db8377fe04ce5502792c67d8d3bf9278", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.gz": "b7c0385692fb7218dc16e3935b6181beeaea1adb731a5ca2dc876a3fa825dfbd", + "dist/2023-03-07/rust-std-beta-i686-unknown-linux-musl.tar.xz": "92c608fd3be1bf98ce343f4b42e187fa1182560bfe10a2c3110037b0600f611c", + "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.gz": "97703dfc96fadd27af79faec3b9b14f5e64549870c5451e8ca5023dc97a7253a", + "dist/2023-03-07/rust-std-beta-i686-unknown-uefi.tar.xz": "7470fc83530b83ad3bae30e7185ca54811f97629ef64b70d3fc2fb757639abf7", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "54f2ff0de486ab6e6ed6dae72d798e1fcd4653b7df1f8d4127eb6a6396572081", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "fb3c1a6daec2ae77de369ef6bd93955d67e70b7b2799a286d2332f5b7d46b715", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.gz": "4af2c66e9e2b3d4003a47aa638177b256db683f7945fd4cf02122c144736045d", + "dist/2023-03-07/rust-std-beta-mips-unknown-linux-musl.tar.xz": "8f3f4385b4a6fb9f8cbeec20b7f7b794d1374221bcab5c2a5aa59d94acdd6855", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ae14ec5c0ea8629de6b8db2a83a4ceb08be6475a07c89abbd8697f72f9d46427", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e2ddff933278d45c9e2d4e6734babd3b6a1e104325d814c8faecc4a51d197a96", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "d67f7fdfbffcdb4daf134209ae62c051959ef5b450ce12f6ff87b5d7f2d69c7f", + "dist/2023-03-07/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "f5ecb43d0445a03d4677b3a8997f899938755c877bad2262dd88f1c5b2960c1b", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "9a9b36ce50e1167259c43d5dd8669ca26831bf7d2df6162395df6f22b3c3b7cf", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "966d074243e8bdbacbe85fbeae546d9d65b3579015abf18a458798f16ad6c940", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "a64b67a50418e8ced6333075541a30f7272fe11f11160969c92efad447c94ebe", + "dist/2023-03-07/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "f2fee3ae76bb483871b23a4ec1cc22cd89193e087d5389362385d21ddd162392", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "f659bb468e1e4a44288953e654808452f1b08bc7acef546b72e0b31fb3552503", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7be5f817c2cca408804be8f0168e60a407d6088b3758688d2e8a79662b26b340", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "2c988d57deb6d9f88a6ff4180b41a65bd2a69722b6d3dd7a80ecc3bfc1ebda0b", + "dist/2023-03-07/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "8e852cb52c7189a5de0274bc592a720ab1d657f39dd689aea0c11cc8d45b7441", + "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "24db414fdf589e5c686e0c1441b061d82b480a305cf7926d7a54f3ce6bcc48da", + "dist/2023-03-07/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f4a90b86b5cfd448c5b7c1b29b99c0f016d64deeee7bfb98048d8b0215f15174", + "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "9c04535d6ad8a823e94e98e3d8aa300ae7181501dfb9819ddbe072ffefe2df98", + "dist/2023-03-07/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "121faf0e67f1fbf609b6f2746c343b2a7fb7efaf0a7129a9d867e8d8c52d5816", + "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "013b5968c15c7257932ea79c8df23dafdc20606a4dd6e7b7f784d56d59831835", + "dist/2023-03-07/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "26abe47cc533337847c021c08fcb88ec77152b5a33500ab948fc45c8bdab23ee", + "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "c72d7e9f58640933bbe5dc1cd7b0ba87f5080ed397099d04cacad992a989199a", + "dist/2023-03-07/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4ef96cf7f4ad93c41b69e9f6a48937cdfb307d7ec65ab2f475707680f638848a", + "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "b4d5fabcc593313b41bbe1a4a201d2acd23f07ce249b6414bb5fb940df519d90", + "dist/2023-03-07/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "537d209c9ea5a7d7750206612b353d33d54a5c55af45c4e8e4f113c6d561cd5b", + "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "8307dd2783e0ccefb27cd645ab53717c851e91c5c5a2e466bc2ebe00f23afeef", + "dist/2023-03-07/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "f2bb8932f9d2a0e51caf64367bb34d1c30456863d3933c766c69be50c0474ff5", + "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "300892f31875cbca564b54124e85fada8af945247c3a31049e6000494f3a633f", + "dist/2023-03-07/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "ebeb2d2bdace58faca8f5d8d3e06581c30f18ac7e0e096d03fd4444a7ca9b7b4", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "62d9e27a3c321bed86839ce6a492e28aa51b1d70bd1b0ff0d6cf8784ee78c8de", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c876705073fa8735fb3b89453a4cb00c3324d3e8ee570acf3bab21ab0ec0d240", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "97751b6d399463e9dbdae41979d0e6405d0faf90ee859d2bb87787a4146420e4", + "dist/2023-03-07/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "cde9469f915b2f37537da5a596ab75eeeff64affd5f26619cd59dab06c03b13a", + "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "000796b94967c2285fa240542063743d389595aa64a58a64145ca093ae505222", + "dist/2023-03-07/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "3ce3f15333e074060c6fc97f40bc2d41d582744df97c1e4630839a34397e793e", + "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "8a44c200db94509b83ea2bcf3b5ca7b8ff1f3c7aa0c9b7942ee3047b619aa161", + "dist/2023-03-07/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "6484f92b2d2793c47f1665d4c0bb93fe64359a3cafb658957bd3ffa33c3753b2", + "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "d60be45093cbbd1269be0dc0e73ccded00a9b72b65fde8c8c5fb72d79cdcdcf9", + "dist/2023-03-07/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "8b46c3bb7a74116d8dfa69fa46cc70b4771c6a28d73c501bc935573e1d06cd20", + "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.gz": "5caf2b9c9dd509ef50840484b577b6ddac2cda32519b75a97053de85340439df", + "dist/2023-03-07/rust-std-beta-sparcv9-sun-solaris.tar.xz": "bc00a55394520283826011467d9f27c74369d47e3d5bd0f9c7b7cc2f2cf74cac", + "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.gz": "38ab6ccd205e1ae9c7599482927bfe42096ad02cef8660bc9aae345b1081e723", + "dist/2023-03-07/rust-std-beta-thumbv6m-none-eabi.tar.xz": "7d605918c0bf111a02fec102de688bee0f2f18e3583c004571710421741224f8", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc7b6933e5f16bc828b446289c561d9810a977a322bdd9e406fa9c5b3e3e925f", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabi.tar.xz": "d42fffb2fb88bac3090a9d99bfb91405f9bac5b09b88b286f74a85deb31adb2d", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "63619f93d1047979d90cc37f6903d4d34c28c793f5d07d448b8f818049c0694c", + "dist/2023-03-07/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3f9735ea8a2b340803e95d55bbd1d510b501e4cd5844a9334ee9cda5733f17cf", + "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.gz": "73581e242b9f002eb36dcf05594859419cbe77393a8b21e8e1f447aaad05b0d0", + "dist/2023-03-07/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f582f14891696a51458b3fea2db8ad883012aab40a5d8cfe97b420d0ad7ab901", + "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "5036157df192a76a3bc5084e9c4e53d9151871c1bd86851c361a08d09779cb0e", + "dist/2023-03-07/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "6b85161caf4a45bdaff3f5428fc41b7bc81a216484c755b7cab297a4914b7c7f", + "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "b749800ef87d357cc010ba46305d6603a40f7c52be3c1778e6a88a2956b89bc2", + "dist/2023-03-07/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "622dcf6bfae396ddf89dd0935a3269cc4f86f5ccc7c83982a75b915600f19733", + "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "7ec9e547fc95900efd3f04cb6f76213be5da762d997c85e8ea8434cbc0c0eebd", + "dist/2023-03-07/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "358fca90a80aeefdcd829aa6d3a027d81ceec010cc42aef971285c7d31699fd6", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "4d87df24f8c466cf2193eec458ce4033926088004d88b3ec4b9c74ed1d137a8a", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "65ded045c0615432a6017524c24da2e66b3ecd83e8869e382a00f2407fd06441", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "f8e081253423ac6fb29d502267e8fc22a3409965bebdd331dd00420ba609511c", + "dist/2023-03-07/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "c69a893777fc2acc407832752ea51d4bad5c4741c4a256172e4ebddeb5f939a7", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "28a8d21a98af1f950bb3f62d6fd124bc2fab0c0c27a419c1fcc1a84d31191b8c", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "b0a774faa4acdbff7d7581617da76e759e073a8d75b435373d9737c4300a178b", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.gz": "2a785745d3129a25441572d221a30d4108a35abf3bd73a387a5d65a5df82ff18", + "dist/2023-03-07/rust-std-beta-wasm32-unknown-unknown.tar.xz": "b5a50098ad047748644c7f510cb2682c52499d12f02a1e94c59a4f904c8002e6", + "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.gz": "265fa8b315a5d39a35fb8d32d5e46c3c66f9608992a3d708ac90437818cfed45", + "dist/2023-03-07/rust-std-beta-wasm32-wasi.tar.xz": "26839f3ed020dbda8ba893492cf504d565e7e1af7cfec5ad76053443d1022839", + "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.gz": "8322910f96d5e206fc3ad237b4cf456e9fc2be0cbb00a57bfc2625126fe84d12", + "dist/2023-03-07/rust-std-beta-x86_64-apple-darwin.tar.xz": "3b1d0288890649121ed4487ec6ef5986913bcad5d224e8fed6feb5fcf56a3b2c", + "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.gz": "ea0a805d90b4b18c0b525faf4eedd2827d1f009d3c7a5cdc084db60c54e86d72", + "dist/2023-03-07/rust-std-beta-x86_64-apple-ios.tar.xz": "86bbc9cb184cb3c18a0afa1b982e951ee1e2569fca23ae7f85efd29f26e21983", + "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "f6bab7e24104f142c62f6d12585725bca24496d45888b22b07d2cc50f2f7f11a", + "dist/2023-03-07/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "20a1ae7636cc1dd9daec73818ecba60c60162d2a016822f1d3e828f55fc4ef9a", + "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.gz": "78e7cae3d09a115fdd447bac210a78595076c37287b6dc142f9c363d207e16f5", + "dist/2023-03-07/rust-std-beta-x86_64-linux-android.tar.xz": "f37fcdc813462bcd94b0a06e38e665da9e5c1b5704cd029a23498c003a0df0a2", + "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.gz": "afb0facbc35bc80c9f23ba59b9367c95b907c944aa5e1eff0fcf9687ca1089cb", + "dist/2023-03-07/rust-std-beta-x86_64-pc-solaris.tar.xz": "c771fd343a9a2073a8170730936153698d94aed87aa15b52a04075a6bfedd4ba", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "c753b3450a584ec7614e20fe308653c2451cc1910de76da663ee5c53a451004b", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "0d072a92ee2d33dd6b6122d273ba8cdbbc7dbc4cf090ca7abbe08fbfb16d5f86", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "de23d40c1aefa660f1411bb0c17da4f16b093244c0d515861b0866aed1e06b07", + "dist/2023-03-07/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6f7b6070ae06074f338fc9eae327bf219389b5f88ee7ae07eb1e290d277b0f8f", + "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.gz": "f2d68b5119525110c29dbd19a747f3ad632f45facee5c437e6796a2a213c52d3", + "dist/2023-03-07/rust-std-beta-x86_64-sun-solaris.tar.xz": "2da196278cc5a2eba2400d5d2b13fe74b65e9daefda0a6231684baaf76982147", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "c922f51ac5c80630d9cf2b1a0f770bcd1c1d74180a716b9852d37a6621035c38", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "b6ae7c3cd80b12537d0802444be97acf9be5072c058d025ced07398b0651f45c", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "2fa8a0fcba9ecd4ac6c47b22091a4f58708f96197f95dcc8075e80a4256fdb0e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "025575e750bc2e1b43e7bf288a87059c96629d0d7290a57cfd0e31f2d0efb9aa", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.gz": "8cfc61094c5ea8eec46131c17deaa8dfaa900f75300b996abd167f527defbb3f", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-illumos.tar.xz": "2e7c57376dbf890dc7d6bb7a0b555ee791b147aea4924882a3a94f9b75347f43", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "4840a693353f759d2d9e3fa40df97f200f27106159a9b126698a6ce07c3a117c", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "9a13a8c8e16028d0e07608da8fbd0ea5b51d9d425230712adcbac679ef5fef9d", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "0ac015df12c5212ac61b5a691d982a4fd64a8f77653b3d41e47da974abecda9f", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "bc12d3599f60a5860a15958ea7d4dc537d64802a23bc75e37a7381d875d3de2d", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "10ae35f994f504db3f58f098e8af9bc15f0c8e878b0af8487b6975846dcaf5ee", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "6d46f12168472f6a82980987d02b7e646a0814219c809ce04c352048be0a2981", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "978d7e3df8d6a16af9461eed0fdf79745c8a3ac91dc7e53ac4670e1991916e59", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f936f6d186df0efcbf1655e7d2436bdebf5cd56ff811802c9ff753f20f38579e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.gz": "9c76650dd06c6d679716e4215259720ff5abed7731621617b9a785bb1c1f3c88", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-none.tar.xz": "4ec0d0b2dc4d163db2967df2f16dfd822adba2d85e85fcb21984c84377b4a5c2", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.gz": "701342db468d8bd5c08b962adf3b2c34d83a10fe81936d3b91937b5667e3f5e9", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-redox.tar.xz": "1c32cbb84bf8f967de3fe71e63c3c0d28c799276d9c2b5f2b3afbe87e57f026a", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.gz": "51492e36780f026b1485d2c0394bc232d8825f3317fd438b1f8eaf9b8d50712e", + "dist/2023-03-07/rust-std-beta-x86_64-unknown-uefi.tar.xz": "33e46267265e9ec7394932b197c598d48147a119bd7346614714590181c84884", + "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.gz": "16927a64c3e0737274ebe4c8e6423977d5f2d684751f678fd2dc5c6a6020ab4b", + "dist/2023-03-07/rustc-beta-aarch64-apple-darwin.tar.xz": "66f758933129e0b1856b477f364e04187316227b4853aee8a5f95f6c7ad60fac", + "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "10a7cd771929aee13937bab01ad1e6d19998cc4ef58816ad8306539140fe3dfc", + "dist/2023-03-07/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "1d9ce8c7728b1831ce564df9a8ee9502ddcfd83c764d0f8c5b941a9beb570fb9", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d75924fdcaa76b064d018e612457a4f960536c51767f46fe20d5e90d41424d45", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "1956f0965e3065a5901f935c42b10e07783ca33a2a8b6f182a5104edc4d73a01", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40fbf2a72485dadf04eaf2a128f631c02542cb53f0d2b2c26369e8b8ee08463a", + "dist/2023-03-07/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "cb7f9812a09ec7397ccb67f36484ce22425446940b65cdc4c72e823a6fab5ec1", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "bc95e80e02e822913eadf5319253e7422615468db1c9627d394992319c3e4d5d", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "5b089b4b531cbd43909518093f6cfb1e5d4df138ede86ef7cc0e0e1053a43452", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "030d2ec4494c9139966cbb833c1616a78b973f10409defbb39f936652ef97449", + "dist/2023-03-07/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "2b2a728780b1bd30ec0cbcf014cb8914ed423a46a97f330c23b7386d8aec2ab7", + "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "2406baa5db6a46e51c79201fde893089ad16f31a17b117509774ee76f16bcdad", + "dist/2023-03-07/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d121bf988fe4225d1cee4b452a0d5aa1620c990456dd9002c0af179802dc33c8", + "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.gz": "eb5d4ae35799c3ddacc77e946b9fe8c1ba88f193c14c58ff23ee7ad89bdc6d9d", + "dist/2023-03-07/rustc-beta-i686-pc-windows-gnu.tar.xz": "1aeb85967f6de2267024abab0bb46dec4ce3bd06e687af39745cb556c37a82fb", + "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.gz": "be2b29bd8ac4214eb5dff5f51c30cabfe859bc02b994c87cb139af50889abced", + "dist/2023-03-07/rustc-beta-i686-pc-windows-msvc.tar.xz": "1c097877d03021b975f2968bda73301a541b7989eb217537ffa3ae079e576c5e", + "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3066f0d3b0e0319c8e9bfcc2215bb16729611563cedb976de0356a050ea68357", + "dist/2023-03-07/rustc-beta-i686-unknown-linux-gnu.tar.xz": "3908a8675f8b5743ce407e12cd0a32f0144db9b38bb49f05c47e855973d1e8c8", + "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.gz": "7aad6a6e37fb7f4fe835c2bbe7d1deb36ef973b7c94f3969b003812f87a92ff0", + "dist/2023-03-07/rustc-beta-mips-unknown-linux-gnu.tar.xz": "29e434023a1d94aaa5003723e2bcd31588d674f2ae243109e34f8e88e141c58c", + "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "4b2e92cd5a01df031060d03d088829056039951ce8b7edd9549944a6f567e07e", + "dist/2023-03-07/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "7e82c3f1a6d5175e452abd4f321469063cb2007f9f33cb3302a5745f985aefb5", + "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b9fb2eb2f43b7479efb227964141f3beb29db829f449830ee41ac83280366ac7", + "dist/2023-03-07/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c4eedd1aa5ac1532387a3091525d9d94fa7979002e0399b351bdd8d3bd064475", + "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "03685364b7750002a9a88717170c4330052c0838de82727734ebcb2d8b0466bc", + "dist/2023-03-07/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "13834ad521e7a3439c56dac58a548f816a60cc2b4f0d25952fb610b0245cd141", + "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "840a15c851f96e9b6b662d0b39c947b922e54195b07822ab6b1e13d5c8206a32", + "dist/2023-03-07/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "5721cb8347f4e9e546a59cec5c89ff548a2dbe867e27107678da6862a435781f", + "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "bb0c56acb9bb9940e970f23649f0d41338950f2e1c97cbca5e2de673069dca54", + "dist/2023-03-07/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "89c102653c6d4f562ad32fbc2d1b82ef38917528a7da6a3219f7b232dac62fcd", + "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "7ca86f54a307ec8e4751a58d541745c900813ef9b355ba21442629ef6d965ea1", + "dist/2023-03-07/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c88a9c0581a8e3d119c57b9825ea8052e448871ed9c64f7530528e7fc833acaa", + "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "48f8abaffc106eba05c903ec250aeff17a71efa88702459da0ba8be58e62c8c4", + "dist/2023-03-07/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "04c176b55b9fdb2fc123e1e012fb8e2dc3bee74861b6cfedf2c1ffbbb3320293", + "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a908e7f868fcd71050f57e08d15648cd6da04a0f9d150d87739349fb9c87a515", + "dist/2023-03-07/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "75062df65fbf89ab1d5344a3471e2c6322f9124fb447b32f634fb6d41695d5c7", + "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.gz": "df5224bb128f668474b9702457f5a349144b3148f44ae77109c7ad78800a4c42", + "dist/2023-03-07/rustc-beta-x86_64-apple-darwin.tar.xz": "9d27f437e483025cbdb69804f05138ebf181dceda8d32a676ea72ea4f27e69c3", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "a7f05d2072c3d3eb7ea88c09ec24a2ce0007ad31df5d3405c6766a68f2fd8ff4", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5e6477ac67b7db05caf15704541db112846415523c483df123d5f566e33afae4", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3a9fd984f8a6673494859dce2dda6be7293effdc3ff7b4620b1078ba346150eb", + "dist/2023-03-07/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "5a12779df3e03ecb9ec334c02245f4dd779a4763ee789a9d6c72c244fed5b444", + "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.gz": "dd04e308e72a9cee60db732a17f12e1acbf279fd07efc232648087b765338f44", + "dist/2023-03-07/rustc-beta-x86_64-unknown-freebsd.tar.xz": "1dd44474ba9956abcdb0aa9d50c39fc7dcc3a78cd56450009bf4ee10cd94ef2e", + "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.gz": "0db8082563772e480dfa71851182fd8a45cf6776d486e02204d92af0784c86a6", + "dist/2023-03-07/rustc-beta-x86_64-unknown-illumos.tar.xz": "eef088e452e105bffe4d28d38d1eacd4982253f0d59cdeb1f406068961699e0c", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "b767ffb06f21b1be530d79a81d8550680d15fd511de5cafae6da9da71017362b", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "d62e8956025dca9d6a9259cc8a35c6d364d161648adb91b50f1fe7e2aec5eb1b", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "aeb32342fc36171ae54b8677348dee02b10207bc85da773a1c7bacfac5e736fb", + "dist/2023-03-07/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b051ffe45858f1ae2e60461183e4181a1b5c3fa4b349788416fb80b3e3fe39ea", + "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2e5ed0ad450602ce32de9509e5317b1b205d4b715f716befb0389f6f6ad94cda", + "dist/2023-03-07/rustc-beta-x86_64-unknown-netbsd.tar.xz": "9347db918ca8139f0d816f297d327f48039f02e1d9d9f443fc0f46fb260c8901", + "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.gz": "034c90c20d39fd2384b03ad2a756d3ca28a7447423bd709a0ade19374aa0fb05", + "dist/2023-03-07/rustc-nightly-aarch64-apple-darwin.tar.xz": "89d6d968fd5e55a950a798f06a09e1a776cf11dccc94b8123c21c55ebf55e9b7", + "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "809733a64b50a7c9c637afb442e45c4424a0fec96d921cfb0c8a7b30fa52edf7", + "dist/2023-03-07/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "03057ff6c4ae76618edea292f49abfcdcad09615a6164186348aba218936c3f0", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "e34521e27196fae399e0cbec28700ac409a829cf365bf5b9a7dc5530af61b93e", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "e17a9773d58ff0f48cce6c86326cbc33c4e0e8ce08f1a6d475481af9771ae6d6", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "01fffcbc734b7de28773a658178534a2cd4d262b156161abd6e5d1d471b45181", + "dist/2023-03-07/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "84c0c9d65f00f259df87e78bbe03d0f31075e70b71c587ca580e63604ee654e9", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "215cc518a7caacd106ffaaf28f709d1ddb3b4595acdf8574866d4e351576330d", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "f50d088adf616f3c25d095254b93d9032a41e5c6a3906afee959b223d6205dfe", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a902efadc47040841653e67f918814a16242312c79ef11c10d69ba9999473c88", + "dist/2023-03-07/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "d608e664a5ce02b246b6b00910bdcb5f09e565e41cefbbb8efc579ac9a73c810", + "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "9e8151095f851f71c1d72d41e4ac63ee0dcc81d0f172ce9df4143b6499047aff", + "dist/2023-03-07/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "285530c33e600a4df44fd06abeac8e48aa5c084386c4cbe78e797c54f85d01ec", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.gz": "c0e245e17691d38d9f69164e5d9e02d08b5c2355f6fa9cea4bacf50af672c67f", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-gnu.tar.xz": "d0c0e699cde96fb23ad5bcc7a8dbf94c86271404b72055bd3382eb29ae4ea85a", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.gz": "b083a065a973394293c11369199385a96d79a6cac5c9d695848e7ac2e51507af", + "dist/2023-03-07/rustc-nightly-i686-pc-windows-msvc.tar.xz": "b819b9af08383249f99f0137b636ac42ce84e3e5220c9e0fc1d9e0d348dca54f", + "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "7337d5bc52c0e18c24546b04777ac24461b34e31a59d7df1611f70aee483528f", + "dist/2023-03-07/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "efaae84475ddb1845fca470d6d77d842da4e2ad0cca0b2c1e9210c6fce3ff08c", + "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.gz": "bd12029bcf9539959c9c9451093cf51ed9db6c7e26b9b9a3bf8617e481b9f094", + "dist/2023-03-07/rustc-nightly-mips-unknown-linux-gnu.tar.xz": "b9ea393526c68b9b502d81387cd4a1db7eeddad61467d2442be7c30d210727d8", + "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "997b37b199cc270b5a832aa608d18e0005a510efb587f154f899a22fb7f13639", + "dist/2023-03-07/rustc-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "e66332078213bf0cce845605d2f7faf28d859e3a98d12d61737ef782a9bdb187", + "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8a7cbbeb0a9f82333068b51c49d33f694d91da327b1169bc44e9d570840d48d8", + "dist/2023-03-07/rustc-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "5eb5e2e270a4a475ef2933fe34c764dc6cfaaae423b0d1acb5313fda970f98ba", + "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.gz": "3140ecca2db80b80118a08cc3fc7ac2989054338525bcc1fe0e2ef1fb5f742bd", + "dist/2023-03-07/rustc-nightly-mipsel-unknown-linux-gnu.tar.xz": "0432d418a81564af612a5dac562d7f4d72d7a18ac25260ad183609380efb6bc5", + "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "5be5fa12eafd82618c1f3f611351f23af1150c48b5e02f80f5b4252ec45c11dc", + "dist/2023-03-07/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "c288c46b8f077ee604d6de6286dc908086383be91ba17700c3f6273d064c6d82", + "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "de3fe2a9c4c87c5d622a1375dd4fd68064bcd2e5c36dbbc92b95ee42c8ad839e", + "dist/2023-03-07/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "b2fbb76cc9e323d0e61d927d7aceff561074b6dbf9907ed3c8dfd867d1308bd8", + "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "f16e202e7e2cfc3a47a0eddd5271fd3a9b7bac5f3c476ce619a249b88cc3ef0b", + "dist/2023-03-07/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "61a1cc7f9ce2e8d8ce62165ae7e8b8a53d5c78265641553305130f7a66c706ea", + "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "25ed59822afbd23edc354adb7e3bc361be9170ddd44fb15d7434e7240a66637b", + "dist/2023-03-07/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "fdadf6c8d04b99094385b4678015f23da571c3cc134b99e96c3964b15d91d9fe", + "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "b84099f98efd9554a005f8b6d8f15dc9bcd60f9f37856174306873631fa7597c", + "dist/2023-03-07/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "608f5a3a1628306618126f94349171566d9a38f14f58875ec1b1e990bd7b1b20", + "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.gz": "4d8b094bf5c608b55e5b618838dafff4b701be093d42aea388c998c2676b226a", + "dist/2023-03-07/rustc-nightly-x86_64-apple-darwin.tar.xz": "f11249dc7fd5d208b10b9ead00dc8baa410ce92f61f597e3a550c138e9145413", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "db689e50dbef48555609217d09205cd1e397770469a82a9c0ad1f2cf1dd1643b", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "36160f7b9a98a463d4e62ed18ff59f5aa34aedf25cf7a7bbd1e4f93dfbfc4a60", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "0b10bbbf73fa9a9524746b080d44bcb29d31f013ab809b4c06a71e626f637b4a", + "dist/2023-03-07/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a96259b26388fbf7907df887aacd8059f87207b46bb84ca9b87c460040a17d21", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "0327b112309ab37508c5bd814a77a50e8eb86b19705758ee0a3c09cc560f89cc", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "a7715f358798fc2f78ae6cb08b46f58ad577b91d0aa286893f8f51fda6b2de57", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.gz": "ed8d664f8609211b3eff0a606f1d5b5f46eb8ab0095df626a26c3abccc518fab", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-illumos.tar.xz": "10badd3e994e93bf48ff1aafc7c056ac525afd12ac4761c0be7af94e361faad5", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "77b7bf994db683057ce94871fb288a24ba41d9a8f5441dfa9a39f3e772f295e3", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "738db7237b08938d978a00b5b972f4c52f36a128ba103ddb67318a905c7e2d27", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "50c57bbf49ec12092dad9de0e559c18f2049de07a0edac4b596a71a2f25a5e0f", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "31af1fbb0f1288e6d7b8eb594cb1936257603038c1ce8b89399056f5d3e1e9c4", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "0a9e395f0b74cc945458d4ad4176567e86cfded1a594eaa485baadb4794dcb64", + "dist/2023-03-07/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "26ff4a12db2b583e2e0b87aeb3d3eb9d1edc3478bfd40ffeb7ebdbfb8d8b2987", + "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "498c7ca27319868d6d2cfb9448b516de1a12076523f092d6c0df10848ba73ff5", + "dist/2023-03-07/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "eec9591d608e13c34fc8108fe976ae2085d688416d82c71bf18f3b00e35a1442", + "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e9822c7e59218e75af96657bc8a5c3a20c77209f6f1d8861c626aabe7ba9a61d", + "dist/2023-03-07/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "dbad704c1fcfbd8562f366017c514aa90874de6028a9b41764ab7d78a72df6bf", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "5529210f57a0128889c19491846ff7c6f214d3a81d0619ee8dbd840f5f6f84a7", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "d59160d2f737322d401e864ae6b7be47f784a334c7cb378a0bbc2769e975945a", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "ab98e6c8fa7998065e0aaf211559d71405cc6e1910e3799889a27bdeea8c620f", + "dist/2023-03-07/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "04ca84fc64c1d211bd29f99b278d9072babbd1e0e9009d9f6f8f1b05f93a70ca", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "e80942fde81d3b54c4d0fc73576eebcda215535e4d80093f2a68f434958c0d9a", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "a9f10f9a51d3e3564f40c65f6d50c8ef67b4e074981f06f4d3b66aa398883f42", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a5566343b6e3abadb152cd4a325735830aa9a60d5f2f87ef1aff66bbde276b14", + "dist/2023-03-07/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "9682e6c4a153d5083b0b360ed9248772da89f05f1142a6f297fc67218b60f298", + "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "51c14ab7679c23825e3a5b9637035768fd43f1e2787a12e431699710f4324998", + "dist/2023-03-07/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "f44893b879649a288c77b826e7e10202a2d3a5b8a8b123d8a030e69671a3ac43", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "7d5a0e567d8efd65b06b4a75ddc50e7bc2e36b42abaeab15147e970688c0bd07", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "541d5cb3d7beff1c0f9f2ea4a521303a372c2b6f4476d76bcfce4974a2753dfa", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "ccc65022f10cf0d7b8228806742c5163cd77edfcc2624894b96b2c9d6d974da4", + "dist/2023-03-07/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "fccfae7200edd30cd1b6083d00a400641b77e0a4a6e3bf2573710964c896c0d1", + "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "eed06879dacc571c289745a943de9bde2e39bee79ab5a5de0304fdc00e116855", + "dist/2023-03-07/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "cb1ed1cf09ce5cdbec931ea27b6fccd37b63108c780ae21c1756c68e0415c59b", + "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "b0681834694c5aa27c404d2328a5ce3e3dcc8a0b146fcd9d47113655cf94c948", + "dist/2023-03-07/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a246b3e7c6ad436ad7523607bcf3a1fc42a66dd9da6a401fdaba5724fdf6801c", + "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "fa5b4d24c046b01b981fb81540155af5677490f2ac151418fa7791ec0f5aed56", + "dist/2023-03-07/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "b28148883461e905440ba25f755dc6a46c393a69a4cea48044e376fb90caa44b", + "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "ff37f00813b2ef0c206fb66cd383f87a089fad6a3746a9d62b27109557eb0097", + "dist/2023-03-07/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "2132cfd61404cfdad4e21ad95066836c77863756d46abc1fd2b702f46b3c7fac", + "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "89d1e41fd9bdd76c15faba83abfa1ffdadfffb6cd1b49c18e2d1333856296ee3", + "dist/2023-03-07/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "2353107ac3875f9cdf690b6684941c2def1c240416208dee58f58e78eefbd96e", + "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b6e0882de92b73d540d22df393750646487dcf12c11b0bdad01265ce5cd6275f", + "dist/2023-03-07/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "c64967a706e7448f97d40b50356672b03f2731fde3488084007bbe7cd07409a6", + "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "d7d829f5a23aa25b320cd4f4c12d2db11d7e36c67a9396de7426933169159b62", + "dist/2023-03-07/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1080d035d29fb9f8e1c007796e38164261ba19d4362b847d571eb7d3a6281d5c", + "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "874d841241b37072a6fb6c8d70f0afc9535ffb47793270b3a2a5c96ba46b7ec2", + "dist/2023-03-07/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "7ede80fb9a1aa27380d764d04e587a30fb6aee36138b145e32d518cbe8ec95b5", + "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "e1ec7d8b92740b0dff06e9424ac8d08b64e4aa85c5e8d46f9234fdeab5ad5e44", + "dist/2023-03-07/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "9058714e2f253ca681b24308a59bee006f636dff0b7571ebdf7c7687233b5a2f", + "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6087e0abf78f2cb49240314cd31aa9bbfca02eb4918db4a2aaaa6758e8364560", + "dist/2023-03-07/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "2c775b1d4e2f3218a1d51f8ac79c63e8c2eabc46106e2a38d5bd1febcba7d12b", + "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "3a14e2b54773816cfdee1a835d2f758abfaacef36af6a7744c464b0ce5713c8b", + "dist/2023-03-07/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "3f6f7e5b9180f0114781b776a7f1bca72b208ddd102a9e44cebcd501eea7a31b", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "c92bf50f2a729af4b045184cd984bde0d97979cf8ae35975a1eaad5d8ae04195", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "c62b8f4862d0f8c38b890408c014be5d6d245f2a49d6f31a80c9447bbed4d8b4", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "8452a8704cb04ce2deef2cce2d9f2be066c5bd35aef323877ebef6f8f739710d", + "dist/2023-03-07/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "e694bb8697679196246f13031a9eef5129b0441a8c93c0292382b21cefab39a7", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "37f7ecfc0ba9314b2ec46ce202973cd7e36062a88070427ced9ffed3ad96c685", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "7aef4412810218743a85f1c7cce423394a327a708d31441441050bc1fcae0d80", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "70701d0bc637c282436e9ef6f18dadcb8068305ac64b1abb802bbc5054ff042c", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "2d8e170259a254cf6b1c5749a681040db70e2603b7231082483f03e2714765ba", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "7241cab5f93fc338fbb07acd2d38e2fa8615c4e6ebb0a53f51ac60c23838845f", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "2742e08cf5900ad3002809c632b8b8962325699307943ba2bafa0931204cc787", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "576c17a72e47fc743d60818bbfefe17c0223eb979cfed3046bf4797e6c2a6d26", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "25026a50665f53b7ac3e1e08b3a5a3a526411c8c18be6d64df6ab23ee0819b64", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "773679226499447a48cd823d324fc906a1d93f3fb5abc137920aa67ece410de9", + "dist/2023-03-07/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "53c88668c3c9ab6df7f3cace825a45616909bb28628ee8636a8ce86b77cf4bb5" } } diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index d1d2db27c6f..fe28c526be3 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { Finite }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), - ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), + ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { cx.qpath_res(qpath, path.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index b1bc10802e1..f0a1b1dfe56 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -124,8 +124,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t #[allow(clippy::too_many_lines)] fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult { match expr.kind { - ExprKind::Box(e) - | ExprKind::Unary(_, e) + ExprKind::Unary(_, e) | ExprKind::Cast(e, _) | ExprKind::Type(e, _) | ExprKind::Field(e, _) diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b33a2478172..04225beeb70 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -321,7 +321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { self.has_significant_drop = true; } } - ExprKind::Box(..) | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Unary(..) | diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 5201da52bbf..67618f7038a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -33,10 +33,6 @@ struct SortByKeyDetection { /// contains a and the other replaces it with b) fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { match (&a_expr.kind, &b_expr.kind) { - // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - }, // Two arrays with mirrored contents (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 79c1ae4861e..e3712190e67 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -127,8 +127,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Type(inner, _) | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) - | ExprKind::AddrOf(_, _, inner) - | ExprKind::Box(inner) => has_no_effect(cx, inner), + | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner), ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, field.expr)) @@ -234,8 +233,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec | ExprKind::Type(inner, _) | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) - | ExprKind::AddrOf(_, _, inner) - | ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), + | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), ExprKind::Struct(_, fields, ref base) => { if has_drop(cx, cx.typeck_results().expr_ty(expr)) { None diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 87f966ced0d..ae7d19624ba 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -213,8 +213,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_ } loop { expr = match expr.kind { - ExprKind::Box(e) - | ExprKind::AddrOf(_, _, e) + ExprKind::AddrOf(_, _, e) | ExprKind::Block( &Block { stmts: [], diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index e2d90edec5a..e12681c0a0c 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -380,7 +380,6 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Binary(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Call(..) | hir::ExprKind::Field(..) | hir::ExprKind::If(..) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f31c3fdb095..bc4adf1596d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -395,11 +395,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } self.expr(field!(let_expr.init)); }, - ExprKind::Box(inner) => { - bind!(self, inner); - kind!("Box({inner})"); - self.expr(inner); - }, ExprKind::Array(elements) => { bind!(self, elements); kind!("Array({elements})"); diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 43f0df145f0..d3a6929f67e 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -112,7 +112,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { - ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index ee2f816f181..babbc7294a1 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -199,8 +199,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // Memory allocation, custom operator, loop, or call to an unknown function - ExprKind::Box(_) - | ExprKind::Unary(..) + ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => self.eagerness = Lazy, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0603755f8a9..3a6d23ca5c1 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -249,7 +249,6 @@ impl HirEqInterExpr<'_, '_, '_> { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) && both(le, re, |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r), (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, @@ -628,7 +627,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(j); } }, - ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { + ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); }, ExprKind::Call(fun, args) => { diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 85bf28b708b..44cb5d5756a 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -133,7 +133,6 @@ impl<'a> Sugg<'a> { match expr.kind { hir::ExprKind::AddrOf(..) - | hir::ExprKind::Box(..) | hir::ExprKind::If(..) | hir::ExprKind::Let(..) | hir::ExprKind::Closure { .. } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index d27a20bd4df..86a93f64fb7 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -600,7 +600,6 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, false, e, f)?; }, ExprKind::Block(&Block { expr: Some(e), .. }, _) - | ExprKind::Box(e) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { helper(typeck, true, e, f)?; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a127875b55d..4d9010d3c4b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -278,13 +278,15 @@ impl<'test> TestCx<'test> { Incremental => { let revision = self.revision.expect("incremental tests require a list of revisions"); - if revision.starts_with("rpass") || revision.starts_with("rfail") { + if revision.starts_with("cpass") + || revision.starts_with("rpass") + || revision.starts_with("rfail") + { true } else if revision.starts_with("cfail") { - // FIXME: would be nice if incremental revs could start with "cpass" pm.is_some() } else { - panic!("revision name must begin with rpass, rfail, or cfail"); + panic!("revision name must begin with cpass, rpass, rfail, or cfail"); } } mode => panic!("unimplemented for mode {:?}", mode), @@ -384,6 +386,20 @@ impl<'test> TestCx<'test> { } } + fn run_cpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let proc_res = self.compile_test(WillExecute::No, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("compile-pass tests with expected warnings should be moved to ui/"); + } + } + fn run_rpass_test(&self) { let emit_metadata = self.should_emit_metadata(self.pass_mode()); let should_run = self.run_if_enabled(); @@ -393,17 +409,15 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("compilation failed!", &proc_res); } + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("run-pass tests with expected warnings should be moved to ui/"); + } + if let WillExecute::Disabled = should_run { return; } - // FIXME(#41968): Move this check to tidy? - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - assert!( - expected_errors.is_empty(), - "run-pass tests with expected warnings should be moved to ui/" - ); - let proc_res = self.exec_compiled_test(); if !proc_res.status.success() { self.fatal_proc_rec("test run failed!", &proc_res); @@ -2913,10 +2927,11 @@ impl<'test> TestCx<'test> { fn run_incremental_test(&self) { // Basic plan for a test incremental/foo/bar.rs: // - load list of revisions rpass1, cfail2, rpass3 - // - each should begin with `rpass`, `cfail`, or `rfail` - // - if `rpass`, expect compile and execution to succeed + // - each should begin with `cpass`, `rpass`, `cfail`, or `rfail` + // - if `cpass`, expect compilation to succeed, don't execute + // - if `rpass`, expect compilation and execution to succeed // - if `cfail`, expect compilation to fail - // - if `rfail`, expect execution to fail + // - if `rfail`, expect compilation to succeed and execution to fail // - create a directory build/foo/bar.incremental // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1 // - because name of revision starts with "rpass", expect success @@ -2940,7 +2955,12 @@ impl<'test> TestCx<'test> { print!("revision={:?} props={:#?}", revision, self.props); } - if revision.starts_with("rpass") { + if revision.starts_with("cpass") { + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); + } + self.run_cpass_test(); + } else if revision.starts_with("rpass") { if self.props.should_ice { self.fatal("can only use should-ice in cfail tests"); } @@ -2953,7 +2973,7 @@ impl<'test> TestCx<'test> { } else if revision.starts_with("cfail") { self.run_cfail_test(); } else { - self.fatal("revision name must begin with rpass, rfail, or cfail"); + self.fatal("revision name must begin with cpass, rpass, rfail, or cfail"); } } diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 138a69974e1..b71f48e4644 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -54,8 +54,8 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo + key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-reset20230315 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -106,8 +106,8 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo + key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-reset20230315 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 476075e9c91..bcdb623b090 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -129,18 +129,15 @@ development version of Miri using ./miri install ``` -and then you can use it as if it was installed by `rustup`. Make sure you use -the same toolchain when calling `cargo miri` that you used when installing Miri! -Usually this means you have to write `cargo +miri miri ...` to select the `miri` -toolchain that was installed by `./miri toolchain`. +and then you can use it as if it was installed by `rustup` as a component of the +`miri` toolchain. Note that the `miri` and `cargo-miri` executables are placed +in the `miri` toolchain's sysroot to prevent conflicts with other toolchains. +The Miri binaries in the `cargo` bin directory (usually `~/.cargo/bin`) are managed by rustup. There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -Note that installing Miri like this will "take away" Miri management from `rustup`. -If you want to later go back to a rustup-installed Miri, run `rustup update`. - ### Using a modified standard library Miri re-builds the standard library into a custom sysroot, so it is fairly easy diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 1086d0481c8..b70f7e0e556 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -15,6 +15,8 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +* **Experimental**: Violations of the Tree Borrows aliasing rules, as an optional + alternative to [Stacked Borrows] * **Experimental**: Data races On top of that, Miri will also tell you about memory leaks: when there is memory @@ -225,6 +227,26 @@ degree documented below): reduced feature set. We might ship Miri with a nightly even when some features on these targets regress. +### Running tests in parallel + +Though it implements Rust threading, Miri itself is a single-threaded interpreter. +This means that when running `cargo miri test`, you will probably see a dramatic +increase in the amount of time it takes to run your whole test suite due to the +inherent interpreter slowdown and a loss of parallelism. + +You can get your test suite's parallelism back by running `cargo miri nextest run -jN` +(note that you will need [`cargo-nextest`](https://nexte.st) installed). +This works because `cargo-nextest` collects a list of all tests then launches a +separate `cargo miri run` for each test. You will need to specify a `-j` or `--test-threads`; +by default `cargo miri nextest run` runs one test at a time. For more details, see the +[`cargo-nextest` Miri documentation](https://nexte.st/book/miri.html). + +Note: This one-test-per-process model means that `cargo miri test` is able to detect data +races where two tests race on a shared resource, but `cargo miri nextest run` will not detect +such races. + +Note: `cargo-nextest` does not support doctests, see https://github.com/nextest-rs/nextest/issues/16 + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler @@ -337,9 +359,11 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-disable-data-race-detector` disables checking for data races. Using this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-stacked-borrows` disables checking the experimental - [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. Using this flag is **unsound** - (but the affected soundness rules are experimental). + aliasing rules to track borrows ([Stacked Borrows] and Tree Borrows). + This can make Miri run faster, but it also means no aliasing violations will + be detected. Using this flag is **unsound** (but the affected soundness rules + are experimental). Later flags take precedence: borrow tracking can be reactivated + by `-Zmiri-tree-borrows`. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs @@ -401,6 +425,9 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated value from a load. This can help diagnose problems that disappear under `-Zmiri-disable-weak-memory-emulation`. +* `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the Tree Borrows rules. + The soundness rules are already experimental without this flag, but even more + so with this flag. * `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k. `4` is default for most targets. This value should always be a power of 2 and nonzero. @@ -415,7 +442,7 @@ Some native rustc `-Z` flags are also very relevant for Miri: functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for [Stacked Borrows]. + enables this per default because it is needed for [Stacked Borrows] and Tree Borrows. Moreover, Miri recognizes some environment variables: @@ -481,120 +508,8 @@ binaries, and as such worth documenting: ## Miri `extern` functions Miri provides some `extern` functions that programs can import to access -Miri-specific functionality: - -```rust -#[cfg(miri)] -extern "Rust" { - /// Miri-provided extern function to mark the block `ptr` points to as a "root" - /// for some static memory. This memory and everything reachable by it is not - /// considered leaking even if it still exists when the program terminates. - /// - /// `ptr` has to point to the beginning of an allocated block. - fn miri_static_root(ptr: *const u8); - - // Miri-provided extern function to get the amount of frames in the current backtrace. - // The `flags` argument must be `0`. - fn miri_backtrace_size(flags: u64) -> usize; - - /// Miri-provided extern function to obtain a backtrace of the current call stack. - /// This writes a slice of pointers into `buf` - each pointer is an opaque value - /// that is only useful when passed to `miri_resolve_frame`. - /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. - /// The `flags` argument must be `1`. - fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); - - /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `flags` argument must be `1`, - /// and `MiriFrame` should be declared as follows: - /// - /// ```rust - /// #[repr(C)] - /// struct MiriFrame { - /// // The size of the name of the function being executed, encoded in UTF-8 - /// name_len: usize, - /// // The size of filename of the function being executed, encoded in UTF-8 - /// filename_len: usize, - /// // The line number currently being executed in `filename`, starting from '1'. - /// lineno: u32, - /// // The column number currently being executed in `filename`, starting from '1'. - /// colno: u32, - /// // The function pointer to the function currently being executed. - /// // This can be compared against function pointers obtained by - /// // casting a function (e.g. `my_fn as *mut ()`) - /// fn_ptr: *mut () - /// } - /// ``` - /// - /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. - /// This function can be called on any thread (not just the one which obtained `frame`). - fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; - - /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. - /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. - /// The flags argument must be `0`. - fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); - - /// Miri-provided extern function to begin unwinding with the given payload. - /// - /// This is internal and unstable and should not be used; we give it here - /// just to be complete. - fn miri_start_panic(payload: *mut u8) -> !; - - /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer - /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. - /// - /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because - /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation. - /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so - /// inherits all of its instability. - fn miri_get_alloc_id(ptr: *const ()) -> u64; - - /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all - /// borrow stacks in an allocation. The leftmost tag is the bottom of the stack. - /// The format of what this emits is unstable and may change at any time. In particular, users should be - /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of - /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. - /// - /// This function is extremely unstable. At any time the format of its output may change, its signature may - /// change, or it may be removed entirely. - fn miri_print_borrow_stacks(alloc_id: u64); - - /// Miri-provided extern function to print (from the interpreter, not the - /// program) the contents of a section of program memory, as bytes. Bytes - /// written using this function will emerge from the interpreter's stdout. - fn miri_write_to_stdout(bytes: &[u8]); - - /// Miri-provided extern function to print (from the interpreter, not the - /// program) the contents of a section of program memory, as bytes. Bytes - /// written using this function will emerge from the interpreter's stderr. - fn miri_write_to_stderr(bytes: &[u8]); - - /// Miri-provided extern function to allocate memory from the interpreter. - /// - /// This is useful when no fundamental way of allocating memory is - /// available, e.g. when using `no_std` + `alloc`. - fn miri_alloc(size: usize, align: usize) -> *mut u8; - - /// Miri-provided extern function to deallocate memory. - fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); - - /// Convert a path from the host Miri runs on to the target Miri interprets. - /// Performs conversion of path separators as needed. - /// - /// Usually Miri performs this kind of conversion automatically. However, manual conversion - /// might be necessary when reading an environment variable that was set on the host - /// (such as TMPDIR) and using it as a target path. - /// - /// Only works with isolation disabled. - /// - /// `in` must point to a null-terminated string, and will be read as the input host path. - /// `out` must point to at least `out_size` many bytes, and the result will be stored there - /// with a null terminator. - /// Returns 0 if the `out` buffer was large enough, and the required size otherwise. - fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize; -} -``` +Miri-specific functionality. They are declared in +[/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs). ## Contributing and getting help diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index 60450d09815..ef52a37fe31 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -62,8 +62,8 @@ function run_tests { if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then # These act up on Windows (`which miri` produces a filename that does not exist?!?), # so let's do this only on Linux. Also makes sure things work without these set. - export RUSTC=$(which rustc) - export MIRI=$(which miri) + export RUSTC=$(which rustc) # Produces a warning unless we also set MIRI + export MIRI=$(rustc +miri --print sysroot)/bin/miri fi mkdir -p .cargo echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml diff --git a/src/tools/miri/miri b/src/tools/miri/miri index 0c0bbbc7020..1073ff499ba 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -6,8 +6,8 @@ USAGE=$(cat <<"EOF" ./miri install <flags>: Installs the miri driver and cargo-miri. <flags> are passed to `cargo install`. Sets up the rpath such that the installed binary should work in any -working directory. However, the rustup toolchain when invoking `cargo miri` -needs to be the same one used for `./miri install`. +working directory. Note that the binaries are placed in the `miri` toolchain +sysroot, to prevent conflicts with other toolchains. ./miri build <flags>: Just build miri. <flags> are passed to `cargo build`. @@ -281,8 +281,9 @@ find_sysroot() { case "$COMMAND" in install) # "--locked" to respect the Cargo.lock file if it exists. - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@" - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@" + # Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains. + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --root "$SYSROOT" "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --root "$SYSROOT" "$@" ;; check) # Check, and let caller control flags. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 53ec1ba0821..18c2561242a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c4e0cd966062ca67daed20775f4e8a60c28e57df +511364e7874dba9649a264100407e4bffe7b5425 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index a2caeb97297..6fe3fa7fb1b 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -32,7 +32,7 @@ use rustc_middle::{ }; use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace}; -use miri::{BacktraceStyle, ProvenanceMode, RetagFields}; +use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -317,6 +317,8 @@ fn main() { miri_config.validate = false; } else if arg == "-Zmiri-disable-stacked-borrows" { miri_config.borrow_tracker = None; + } else if arg == "-Zmiri-tree-borrows" { + miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows); } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; miri_config.weak_memory_emulation = false; diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 9f6cbe7f3c7..ed958329f95 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -11,6 +11,7 @@ use rustc_target::abi::Size; use crate::*; pub mod stacked_borrows; +pub mod tree_borrows; pub type CallId = NonZeroU64; @@ -230,8 +231,10 @@ impl GlobalStateInner { /// Which borrow tracking method to use #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BorrowTrackerMethod { - /// Stacked Borrows, as implemented in borrow_tracker/stacked + /// Stacked Borrows, as implemented in borrow_tracker/stacked_borrows StackedBorrows, + /// Tree borrows, as implemented in borrow_tracker/tree_borrows + TreeBorrows, } impl BorrowTrackerMethod { @@ -258,6 +261,10 @@ impl GlobalStateInner { AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation( id, alloc_size, self, kind, machine, )))), + BorrowTrackerMethod::TreeBorrows => + AllocState::TreeBorrows(Box::new(RefCell::new(Tree::new_allocation( + id, alloc_size, self, kind, machine, + )))), } } } @@ -273,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_ptr_value(kind, val), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_ptr_value(kind, val), } } @@ -285,6 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_place_contents(kind, place), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_place_contents(kind, place), } } @@ -293,6 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_retag_return_place(), + BorrowTrackerMethod::TreeBorrows => this.tb_retag_return_place(), } } @@ -301,6 +311,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { BorrowTrackerMethod::StackedBorrows => this.sb_expose_tag(alloc_id, tag), + BorrowTrackerMethod::TreeBorrows => this.tb_expose_tag(alloc_id, tag), + } + } + + fn give_pointer_debug_name( + &mut self, + ptr: Pointer<Option<Provenance>>, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; + match method { + BorrowTrackerMethod::StackedBorrows => { + this.tcx.tcx.sess.warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op"); + Ok(()) + } + BorrowTrackerMethod::TreeBorrows => + this.tb_give_pointer_debug_name(ptr, nth_parent, name), + } + } + + fn print_borrow_state(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; + match method { + BorrowTrackerMethod::StackedBorrows => this.print_stacks(alloc_id), + BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed), } } } @@ -310,6 +348,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pub enum AllocState { /// Data corresponding to Stacked Borrows StackedBorrows(Box<RefCell<stacked_borrows::AllocState>>), + /// Data corresponding to Tree Borrows + TreeBorrows(Box<RefCell<tree_borrows::AllocState>>), } impl machine::AllocExtra { @@ -328,6 +368,14 @@ impl machine::AllocExtra { _ => panic!("expected Stacked Borrows borrow tracking, got something else"), } } + + #[track_caller] + pub fn borrow_tracker_tb(&self) -> &RefCell<tree_borrows::AllocState> { + match self.borrow_tracker { + Some(AllocState::TreeBorrows(ref tb)) => tb, + _ => panic!("expected Tree Borrows borrow tracking, got something else"), + } + } } impl AllocState { @@ -341,6 +389,14 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.borrow_mut().before_memory_access( + AccessKind::Read, + alloc_id, + prov_extra, + range, + machine, + ), } } @@ -354,6 +410,14 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.get_mut().before_memory_access( + AccessKind::Write, + alloc_id, + prov_extra, + range, + machine, + ), } } @@ -367,12 +431,15 @@ impl AllocState { match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine), + AllocState::TreeBorrows(tb) => + tb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine), } } pub fn remove_unreachable_tags(&self, tags: &FxHashSet<BorTag>) { match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags), + AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags), } } } @@ -381,6 +448,7 @@ impl VisitTags for AllocState { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { match self { AllocState::StackedBorrows(sb) => sb.visit_tags(visit), + AllocState::TreeBorrows(tb) => tb.visit_tags(visit), } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs new file mode 100644 index 00000000000..97bbdee1d44 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -0,0 +1,592 @@ +use rustc_data_structures::fx::FxHashMap; + +use std::fmt; +use std::ops::Range; + +use crate::borrow_tracker::tree_borrows::{ + err_tb_ub, perms::Permission, tree::LocationState, unimap::UniIndex, +}; +use crate::borrow_tracker::{AccessKind, ProtectorKind}; +use crate::*; + +/// Some information that is irrelevant for the algorithm but very +/// convenient to know about a tag for debugging and testing. +#[derive(Clone, Debug)] +pub struct NodeDebugInfo { + /// The tag in question. + pub tag: BorTag, + /// Name(s) that were associated with this tag (comma-separated). + /// Typically the name of the variable holding the corresponding + /// pointer in the source code. + /// Helps match tag numbers to human-readable names. + pub name: Option<String>, +} +impl NodeDebugInfo { + /// New node info with a name. + pub fn new(tag: BorTag) -> Self { + Self { tag, name: None } + } + + /// Add a name to the tag. If a same tag is associated to several pointers, + /// it can have several names which will be separated by commas. + fn add_name(&mut self, name: &str) { + if let Some(ref mut prev_name) = &mut self.name { + prev_name.push(','); + prev_name.push_str(name); + } else { + self.name = Some(String::from(name)); + } + } +} + +impl fmt::Display for NodeDebugInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(ref name) = self.name { + write!(f, "{tag:?} (also named '{name}')", tag = self.tag) + } else { + write!(f, "{tag:?}", tag = self.tag) + } + } +} + +impl<'tcx> Tree { + /// Climb the tree to get the tag of a distant ancestor. + /// Allows operations on tags that are unreachable by the program + /// but still exist in the tree. Not guaranteed to perform consistently + /// if `tag-gc=1`. + fn nth_parent(&self, tag: BorTag, nth_parent: u8) -> Option<BorTag> { + let mut idx = self.tag_mapping.get(&tag).unwrap(); + for _ in 0..nth_parent { + let node = self.nodes.get(idx).unwrap(); + idx = node.parent?; + } + Some(self.nodes.get(idx).unwrap().tag) + } + + /// Debug helper: assign name to tag. + pub fn give_pointer_debug_name( + &mut self, + tag: BorTag, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let tag = self.nth_parent(tag, nth_parent).unwrap(); + let idx = self.tag_mapping.get(&tag).unwrap(); + if let Some(node) = self.nodes.get_mut(idx) { + node.debug_info.add_name(name); + } else { + eprintln!("Tag {tag:?} (to be named '{name}') not found!"); + } + Ok(()) + } + + /// Debug helper: determines if the tree contains a tag. + pub fn is_allocation_of(&self, tag: BorTag) -> bool { + self.tag_mapping.contains_key(&tag) + } +} + +#[derive(Debug, Clone, Copy)] +pub(super) enum TransitionError { + /// This access is not allowed because some parent tag has insufficient permissions. + /// For example, if a tag is `Frozen` and encounters a child write this will + /// produce a `ChildAccessForbidden(Frozen)`. + /// This kind of error can only occur on child accesses. + ChildAccessForbidden(Permission), + /// A protector was triggered due to an invalid transition that loses + /// too much permissions. + /// For example, if a protected tag goes from `Active` to `Frozen` due + /// to a foreign write this will produce a `ProtectedTransition(Active, Frozen)`. + /// This kind of error can only occur on foreign accesses. + ProtectedTransition(Permission, Permission), + /// Cannot deallocate because some tag in the allocation is strongly protected. + /// This kind of error can only occur on deallocations. + ProtectedDealloc, +} + +/// Failures that can occur during the execution of Tree Borrows procedures. +pub(super) struct TbError<'node> { + /// What failure occurred. + pub error_kind: TransitionError, + /// The tag on which the error was triggered. + /// On protector violations, this is the tag that was protected. + /// On accesses rejected due to insufficient permissions, this is the + /// tag that lacked those permissions. + pub faulty_tag: &'node NodeDebugInfo, + /// Whether this was a Read or Write access. This field is ignored + /// when the error was triggered by a deallocation. + pub access_kind: AccessKind, + /// Which tag the access that caused this error was made through, i.e. + /// which tag was used to read/write/deallocate. + pub tag_of_access: &'node NodeDebugInfo, +} + +impl TbError<'_> { + /// Produce a UB error. + pub fn build<'tcx>(self) -> InterpErrorInfo<'tcx> { + use TransitionError::*; + err_tb_ub(match self.error_kind { + ChildAccessForbidden(perm) => { + format!( + "{kind} through {initial} is forbidden because it is a child of {current} which is {perm}.", + kind=self.access_kind, + initial=self.tag_of_access, + current=self.faulty_tag, + perm=perm, + ) + } + ProtectedTransition(start, end) => { + format!( + "{kind} through {initial} is forbidden because it is a foreign tag for {current}, which would hence change from {start} to {end}, but {current} is protected", + current=self.faulty_tag, + start=start, + end=end, + kind=self.access_kind, + initial=self.tag_of_access, + ) + } + ProtectedDealloc => { + format!( + "the allocation of {initial} also contains {current} which is strongly protected, cannot deallocate", + initial=self.tag_of_access, + current=self.faulty_tag, + ) + } + }).into() + } +} + +type S = &'static str; +/// Pretty-printing details +/// +/// Example: +/// ``` +/// DisplayFmtWrapper { +/// top: '>', +/// bot: '<', +/// warning_text: "Some tags have been hidden", +/// } +/// ``` +/// will wrap the entire text with +/// ```text +/// >>>>>>>>>>>>>>>>>>>>>>>>>> +/// Some tags have been hidden +/// +/// [ main display here ] +/// +/// <<<<<<<<<<<<<<<<<<<<<<<<<< +/// ``` +struct DisplayFmtWrapper { + /// Character repeated to make the upper border. + top: char, + /// Character repeated to make the lower border. + bot: char, + /// Warning about some tags (unnamed) being hidden. + warning_text: S, +} + +/// Formating of the permissions on each range. +/// +/// Example: +/// ``` +/// DisplayFmtPermission { +/// open: "[", +/// sep: "|", +/// close: "]", +/// uninit: "___", +/// range_sep: "..", +/// } +/// ``` +/// will show each permission line as +/// ```text +/// 0.. 1.. 2.. 3.. 4.. 5 +/// [Act|Res|Frz|Dis|___] +/// ``` +struct DisplayFmtPermission { + /// Text that starts the permission block. + open: S, + /// Text that separates permissions on different ranges. + sep: S, + /// Text that ends the permission block. + close: S, + /// Text to show when a permission is not initialized. + /// Should have the same width as a `Permission`'s `.short_name()`, i.e. + /// 3 if using the `Res/Act/Frz/Dis` notation. + uninit: S, + /// Text to separate the `start` and `end` values of a range. + range_sep: S, +} + +/// Formating of the tree structure. +/// +/// Example: +/// ``` +/// DisplayFmtPadding { +/// join_middle: "|-", +/// join_last: "'-", +/// join_haschild: "-+-", +/// join_default: "---", +/// indent_middle: "| ", +/// indent_last: " ", +/// } +/// ``` +/// will show the tree as +/// ```text +/// -+- root +/// |--+- a +/// | '--+- b +/// | '---- c +/// |--+- d +/// | '---- e +/// '---- f +/// ``` +struct DisplayFmtPadding { + /// Connector for a child other than the last. + join_middle: S, + /// Connector for the last child. Should have the same width as `join_middle`. + join_last: S, + /// Connector for a node that itself has a child. + join_haschild: S, + /// Connector for a node that does not have a child. Should have the same width + /// as `join_haschild`. + join_default: S, + /// Indentation when there is a next child. + indent_middle: S, + /// Indentation for the last child. + indent_last: S, +} +/// How to show whether a location has been accessed +/// +/// Example: +/// ``` +/// DisplayFmtAccess { +/// yes: " ", +/// no: "?", +/// meh: "_", +/// } +/// ``` +/// will show states as +/// ```text +/// Act +/// ?Res +/// ____ +/// ``` +struct DisplayFmtAccess { + /// Used when `State.initialized = true`. + yes: S, + /// Used when `State.initialized = false`. + /// Should have the same width as `yes`. + no: S, + /// Used when there is no `State`. + /// Should have the same width as `yes`. + meh: S, +} + +/// All parameters to determine how the tree is formated. +struct DisplayFmt { + wrapper: DisplayFmtWrapper, + perm: DisplayFmtPermission, + padding: DisplayFmtPadding, + accessed: DisplayFmtAccess, +} +impl DisplayFmt { + /// Print the permission with the format + /// ` Res`/` Re*`/` Act`/` Frz`/` Dis` for accessed locations + /// and `?Res`/`?Re*`/`?Act`/`?Frz`/`?Dis` for unaccessed locations. + fn print_perm(&self, perm: Option<LocationState>) -> String { + if let Some(perm) = perm { + format!( + "{ac}{st}", + ac = if perm.is_initialized() { self.accessed.yes } else { self.accessed.no }, + st = perm.permission().short_name(), + ) + } else { + format!("{}{}", self.accessed.meh, self.perm.uninit) + } + } + + /// Print the tag with the format `<XYZ>` if the tag is unnamed, + /// and `<XYZ=name>` if the tag is named. + fn print_tag(&self, tag: BorTag, name: &Option<String>) -> String { + let printable_tag = tag.get(); + if let Some(name) = name { + format!("<{printable_tag}={name}>") + } else { + format!("<{printable_tag}>") + } + } + + /// Print extra text if the tag has a protector. + fn print_protector(&self, protector: Option<&ProtectorKind>) -> &'static str { + protector + .map(|p| { + match *p { + ProtectorKind::WeakProtector => " Weakly protected", + ProtectorKind::StrongProtector => " Strongly protected", + } + }) + .unwrap_or("") + } +} + +/// Track the indentation of the tree. +struct DisplayIndent { + curr: String, +} +impl DisplayIndent { + fn new() -> Self { + Self { curr: " ".to_string() } + } + + /// Increment the indentation by one. Note: need to know if this + /// is the last child or not because the presence of other children + /// changes the way the indentation is shown. + fn increment(&mut self, formatter: &DisplayFmt, is_last: bool) { + self.curr.push_str(if is_last { + formatter.padding.indent_last + } else { + formatter.padding.indent_middle + }); + } + + /// Pop the last level of indentation. + fn decrement(&mut self, formatter: &DisplayFmt) { + for _ in 0..formatter.padding.indent_last.len() { + let _ = self.curr.pop(); + } + } + + /// Print the current indentation. + fn write(&self, s: &mut String) { + s.push_str(&self.curr); + } +} + +/// Repeat a character a number of times. +fn char_repeat(c: char, n: usize) -> String { + std::iter::once(c).cycle().take(n).collect::<String>() +} + +/// Extracted information from the tree, in a form that is readily accessible +/// for printing. I.e. resolve parent-child pointers into an actual tree, +/// zip permissions with their tag, remove wrappers, stringify data. +struct DisplayRepr { + tag: BorTag, + name: Option<String>, + rperm: Vec<Option<LocationState>>, + children: Vec<DisplayRepr>, +} + +impl DisplayRepr { + fn from(tree: &Tree, show_unnamed: bool) -> Option<Self> { + let mut v = Vec::new(); + extraction_aux(tree, tree.root, show_unnamed, &mut v); + let Some(root) = v.pop() else { + if show_unnamed { + unreachable!("This allocation contains no tags, not even a root. This should not happen."); + } + eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."); + return None; + }; + assert!(v.is_empty()); + return Some(root); + + fn extraction_aux( + tree: &Tree, + idx: UniIndex, + show_unnamed: bool, + acc: &mut Vec<DisplayRepr>, + ) { + let node = tree.nodes.get(idx).unwrap(); + let name = node.debug_info.name.clone(); + let children_sorted = { + let mut children = node.children.iter().cloned().collect::<Vec<_>>(); + children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag); + children + }; + if !show_unnamed && name.is_none() { + // We skip this node + for child_idx in children_sorted { + extraction_aux(tree, child_idx, show_unnamed, acc); + } + } else { + // We take this node + let rperm = tree + .rperms + .iter_all() + .map(move |(_offset, perms)| { + let perm = perms.get(idx); + perm.cloned() + }) + .collect::<Vec<_>>(); + let mut children = Vec::new(); + for child_idx in children_sorted { + extraction_aux(tree, child_idx, show_unnamed, &mut children); + } + acc.push(DisplayRepr { tag: node.tag, name, rperm, children }); + } + } + } + fn print( + &self, + fmt: &DisplayFmt, + indenter: &mut DisplayIndent, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + ranges: Vec<Range<u64>>, + print_warning: bool, + ) { + let mut block = Vec::new(); + // Push the header and compute the required paddings for the body. + // Header looks like this: `0.. 1.. 2.. 3.. 4.. 5.. 6.. 7.. 8`, + // and is properly aligned with the `|` of the body. + let (range_header, range_padding) = { + let mut header_top = String::new(); + header_top.push_str("0.."); + let mut padding = Vec::new(); + for (i, range) in ranges.iter().enumerate() { + if i > 0 { + header_top.push_str(fmt.perm.range_sep); + } + let s = range.end.to_string(); + let l = s.chars().count() + fmt.perm.range_sep.chars().count(); + { + let target_len = + fmt.perm.uninit.chars().count() + fmt.accessed.yes.chars().count() + 1; + let tot_len = target_len.max(l); + let header_top_pad_len = target_len.saturating_sub(l); + let body_pad_len = tot_len.saturating_sub(target_len); + header_top.push_str(&format!("{}{}", char_repeat(' ', header_top_pad_len), s)); + padding.push(body_pad_len); + } + } + ([header_top], padding) + }; + for s in range_header { + block.push(s); + } + // This is the actual work + print_aux( + self, + &range_padding, + fmt, + indenter, + protected_tags, + true, /* root _is_ the last child */ + &mut block, + ); + // Then it's just prettifying it with a border of dashes. + { + let wr = &fmt.wrapper; + let max_width = { + let block_width = block.iter().map(|s| s.chars().count()).max().unwrap(); + if print_warning { + block_width.max(wr.warning_text.chars().count()) + } else { + block_width + } + }; + eprintln!("{}", char_repeat(wr.top, max_width)); + if print_warning { + eprintln!("{}", wr.warning_text,); + } + for line in block { + eprintln!("{line}"); + } + eprintln!("{}", char_repeat(wr.bot, max_width)); + } + + // Here is the function that does the heavy lifting + fn print_aux( + tree: &DisplayRepr, + padding: &[usize], + fmt: &DisplayFmt, + indent: &mut DisplayIndent, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + is_last_child: bool, + acc: &mut Vec<String>, + ) { + let mut line = String::new(); + // Format the permissions on each range. + // Looks like `| Act| Res| Res| Act|`. + line.push_str(fmt.perm.open); + for (i, (perm, &pad)) in tree.rperm.iter().zip(padding.iter()).enumerate() { + if i > 0 { + line.push_str(fmt.perm.sep); + } + let show_perm = fmt.print_perm(*perm); + line.push_str(&format!("{}{}", char_repeat(' ', pad), show_perm)); + } + line.push_str(fmt.perm.close); + // Format the tree structure. + // Main difficulty is handling the indentation properly. + indent.write(&mut line); + { + // padding + line.push_str(if is_last_child { + fmt.padding.join_last + } else { + fmt.padding.join_middle + }); + line.push_str(fmt.padding.join_default); + line.push_str(if tree.children.is_empty() { + fmt.padding.join_default + } else { + fmt.padding.join_haschild + }); + line.push_str(fmt.padding.join_default); + line.push_str(fmt.padding.join_default); + } + line.push_str(&fmt.print_tag(tree.tag, &tree.name)); + let protector = protected_tags.get(&tree.tag); + line.push_str(fmt.print_protector(protector)); + // Push the line to the accumulator then recurse. + acc.push(line); + let nb_children = tree.children.len(); + for (i, child) in tree.children.iter().enumerate() { + indent.increment(fmt, is_last_child); + print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc); + indent.decrement(fmt); + } + } + } +} + +const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt { + wrapper: DisplayFmtWrapper { + top: '─', + bot: '─', + warning_text: "Warning: this tree is indicative only. Some tags may have been hidden.", + }, + perm: DisplayFmtPermission { open: "|", sep: "|", close: "|", uninit: "---", range_sep: ".." }, + padding: DisplayFmtPadding { + join_middle: "├", + join_last: "└", + indent_middle: "│ ", + indent_last: " ", + join_haschild: "┬", + join_default: "─", + }, + accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" }, +}; + +impl<'tcx> Tree { + /// Display the contents of the tree. + pub fn print_tree( + &self, + protected_tags: &FxHashMap<BorTag, ProtectorKind>, + show_unnamed: bool, + ) -> InterpResult<'tcx> { + let mut indenter = DisplayIndent::new(); + let ranges = self.rperms.iter_all().map(|(range, _perms)| range).collect::<Vec<_>>(); + if let Some(repr) = DisplayRepr::from(self, show_unnamed) { + repr.print( + &DEFAULT_FORMATTER, + &mut indenter, + protected_tags, + ranges, + /* print warning message about tags not shown */ !show_unnamed, + ); + } + Ok(()) + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs new file mode 100644 index 00000000000..2297ceb1259 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -0,0 +1,539 @@ +use log::trace; + +use rustc_target::abi::{Abi, Size}; + +use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields}; +use rustc_middle::{ + mir::{Mutability, RetagKind}, + ty::{ + self, + layout::{HasParamEnv, LayoutOf}, + Ty, + }, +}; + +use crate::*; + +mod diagnostics; +mod perms; +mod tree; +mod unimap; +use perms::Permission; +pub use tree::Tree; + +pub type AllocState = Tree; + +pub fn err_tb_ub<'tcx>(msg: String) -> InterpError<'tcx> { + err_machine_stop!(TerminationInfo::TreeBorrowsUb { msg }) +} + +impl<'tcx> Tree { + /// Create a new allocation, i.e. a new tree + pub fn new_allocation( + id: AllocId, + size: Size, + state: &mut GlobalStateInner, + _kind: MemoryKind<machine::MiriMemoryKind>, + machine: &MiriMachine<'_, 'tcx>, + ) -> Self { + let tag = state.base_ptr_tag(id, machine); // Fresh tag for the root + Tree::new(tag, size) + } + + /// Check that an access on the entire range is permitted, and update + /// the tree. + pub fn before_memory_access( + &mut self, + access_kind: AccessKind, + alloc_id: AllocId, + prov: ProvenanceExtra, + range: AllocRange, + machine: &MiriMachine<'_, 'tcx>, + ) -> InterpResult<'tcx> { + trace!( + "{} with tag {:?}: {:?}, size {}", + access_kind, + prov, + Pointer::new(alloc_id, range.start), + range.size.bytes(), + ); + // TODO: for now we bail out on wildcard pointers. Eventually we should + // handle them as much as we can. + let tag = match prov { + ProvenanceExtra::Concrete(tag) => tag, + ProvenanceExtra::Wildcard => return Ok(()), + }; + let global = machine.borrow_tracker.as_ref().unwrap(); + self.perform_access(access_kind, tag, range, global) + } + + /// Check that this pointer has permission to deallocate this range. + pub fn before_memory_deallocation( + &mut self, + _alloc_id: AllocId, + prov: ProvenanceExtra, + range: AllocRange, + machine: &MiriMachine<'_, 'tcx>, + ) -> InterpResult<'tcx> { + // TODO: for now we bail out on wildcard pointers. Eventually we should + // handle them as much as we can. + let tag = match prov { + ProvenanceExtra::Concrete(tag) => tag, + ProvenanceExtra::Wildcard => return Ok(()), + }; + let global = machine.borrow_tracker.as_ref().unwrap(); + self.dealloc(tag, range, global) + } + + pub fn expose_tag(&mut self, _tag: BorTag) { + // TODO + } +} + +/// Policy for a new borrow. +#[derive(Debug, Clone, Copy)] +struct NewPermission { + /// Whether this borrow requires a read access on its parent. + /// `perform_read_access` is `true` for all pointers marked `dereferenceable`. + perform_read_access: bool, + /// Which permission should the pointer start with. + initial_state: Permission, + /// Whether this pointer is part of the arguments of a function call. + /// `protector` is `Some(_)` for all pointers marked `noalias`. + protector: Option<ProtectorKind>, +} + +impl<'tcx> NewPermission { + /// Determine NewPermission of the reference from the type of the pointee. + fn from_ref_ty( + pointee: Ty<'tcx>, + mutability: Mutability, + kind: RetagKind, + cx: &crate::MiriInterpCx<'_, 'tcx>, + ) -> Option<Self> { + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env()); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env()); + let initial_state = match mutability { + Mutability::Mut if ty_is_unpin => Permission::new_unique_2phase(ty_is_freeze), + Mutability::Not if ty_is_freeze => Permission::new_frozen(), + // Raw pointers never enter this function so they are not handled. + // However raw pointers are not the only pointers that take the parent + // tag, this also happens for `!Unpin` `&mut`s and interior mutable + // `&`s, which are excluded above. + _ => return None, + }; + // This field happens to be redundant since right now we always do a read, + // but it could be useful in the future. + let perform_read_access = true; + + let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector); + Some(Self { perform_read_access, initial_state, protector }) + } + + // Boxes are not handled by `from_ref_ty`, they need special behavior + // implemented here. + fn from_box_ty( + ty: Ty<'tcx>, + kind: RetagKind, + cx: &crate::MiriInterpCx<'_, 'tcx>, + ) -> Option<Self> { + let pointee = ty.builtin_deref(true).unwrap().ty; + pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { + // Regular `Unpin` box, give it `noalias` but only a weak protector + // because it is valid to deallocate it within the function. + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env()); + Self { + perform_read_access: true, + initial_state: Permission::new_unique_2phase(ty_is_freeze), + protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector), + } + }) + } +} + +/// Retagging/reborrowing. +/// Policy on which permission to grant to each pointer should be left to +/// the implementation of NewPermission. +impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx> + for crate::MiriInterpCx<'mir, 'tcx> +{ +} +trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Returns the `AllocId` the reborrow was done in, if there is some actual + /// memory associated with this pointer. Returns `None` if there is no actual + /// memory allocated. Also checks that the reborrow of size `ptr_size` is + /// within bounds of the allocation. + /// + /// Also returns the tag that the pointer should get, which is essentially + /// `if new_perm.is_some() { new_tag } else { parent_tag }` along with + /// some logging (always) and fake reads (if `new_perm` is + /// `Some(NewPermission { perform_read_access: true }`). + fn tb_reborrow( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here + ptr_size: Size, + new_perm: Option<NewPermission>, + new_tag: BorTag, + ) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> { + let this = self.eval_context_mut(); + + // It is crucial that this gets called on all code paths, to ensure we track tag creation. + let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, + loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag + -> InterpResult<'tcx> { + let global = this.machine.borrow_tracker.as_ref().unwrap().borrow(); + let ty = place.layout.ty; + if global.tracked_pointer_tags.contains(&new_tag) { + let kind_str = format!("{new_perm:?} (pointee type {ty})"); + this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag( + new_tag.inner(), + Some(kind_str), + loc.map(|(alloc_id, base_offset, orig_tag)| (alloc_id, alloc_range(base_offset, ptr_size), orig_tag)), + )); + } + drop(global); // don't hold that reference any longer than we have to + Ok(()) + }; + + let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO { + this.ptr_get_alloc_id(place.ptr)? + } else { + match this.ptr_try_get_alloc_id(place.ptr) { + Ok(data) => data, + Err(_) => { + // This pointer doesn't come with an AllocId, so there's no + // memory to do retagging in. + trace!( + "reborrow of size 0: reference {:?} derived from {:?} (pointee {})", + new_tag, + place.ptr, + place.layout.ty, + ); + log_creation(this, None)?; + return Ok(None); + } + } + }; + let orig_tag = match parent_prov { + ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers + ProvenanceExtra::Concrete(tag) => tag, + }; + + // Protection against trying to get a reference to a vtable: + // vtables do not have an alloc_extra so the call to + // `get_alloc_extra` that follows fails. + let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) { + return Ok(Some((alloc_id, orig_tag))); + } + + log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; + + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). + if base_offset + ptr_size > alloc_size { + throw_ub!(PointerOutOfBounds { + alloc_id, + alloc_size, + ptr_offset: this.target_usize_to_isize(base_offset.bytes()), + ptr_size, + msg: CheckInAllocMsg::InboundsTest + }); + } + + trace!( + "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}", + new_tag, + orig_tag, + place.layout.ty, + Pointer::new(alloc_id, base_offset), + ptr_size.bytes() + ); + + let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); }; + + if let Some(protect) = new_perm.protector { + // We register the protection in two different places. + // This makes creating a protector slower, but checking whether a tag + // is protected faster. + this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag); + this.machine + .borrow_tracker + .as_mut() + .expect("We should have borrow tracking data") + .get_mut() + .protected_tags + .insert(new_tag, protect); + } + + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let range = alloc_range(base_offset, ptr_size); + let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); + + if new_perm.perform_read_access { + // Count this reborrow as a read access + let global = &this.machine.borrow_tracker.as_ref().unwrap(); + tree_borrows.perform_access(AccessKind::Read, orig_tag, range, global)?; + if let Some(data_race) = alloc_extra.data_race.as_ref() { + data_race.read(alloc_id, range, &this.machine)?; + } + } + + // Record the parent-child pair in the tree. + tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range)?; + Ok(Some((alloc_id, new_tag))) + } + + /// Retags an indidual pointer, returning the retagged version. + fn tb_retag_reference( + &mut self, + val: &ImmTy<'tcx, Provenance>, + new_perm: Option<NewPermission>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + let this = self.eval_context_mut(); + // We want a place for where the ptr *points to*, so we get one. + let place = this.ref_to_mplace(val)?; + + // Get a lower bound of the size of this place. + // (When `extern type` are involved, use the size of the known prefix.) + let size = this + .size_and_align_of_mplace(&place)? + .map(|(size, _)| size) + .unwrap_or(place.layout.size); + + // This new tag is not guaranteed to actually be used. + // + // If you run out of tags, consider the following optimization: adjust `tb_reborrow` + // so that rather than taking as input a fresh tag and deciding whether it uses this + // one or the parent it instead just returns whether a new tag should be created. + // This will avoid creating tags than end up never being used. + let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr(); + + // Compute the actual reborrow. + let reborrowed = this.tb_reborrow(&place, size, new_perm, new_tag)?; + + // Adjust pointer. + let new_place = place.map_provenance(|p| { + p.map(|prov| { + match reborrowed { + Some((alloc_id, actual_tag)) => { + // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. + // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. + Provenance::Concrete { alloc_id, tag: actual_tag } + } + None => { + // Looks like this has to stay a wildcard pointer. + assert!(matches!(prov, Provenance::Wildcard)); + Provenance::Wildcard + } + } + }) + }); + + // Return new pointer. + Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Retag a pointer. References are passed to `from_ref_ty` and + /// raw pointers are never reborrowed. + fn tb_retag_ptr_value( + &mut self, + kind: RetagKind, + val: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + let this = self.eval_context_mut(); + let new_perm = if let &ty::Ref(_, pointee, mutability) = val.layout.ty.kind() { + NewPermission::from_ref_ty(pointee, mutability, kind, this) + } else { + None + }; + this.tb_retag_reference(val, new_perm) + } + + /// Retag all pointers that are stored in this place. + fn tb_retag_place_contents( + &mut self, + kind: RetagKind, + place: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; + let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + return visitor.visit_value(place); + + // The actual visitor. + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>, + kind: RetagKind, + retag_fields: RetagFields, + } + impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { + #[inline(always)] // yes this helps in our benchmarks + fn retag_ptr_inplace( + &mut self, + place: &PlaceTy<'tcx, Provenance>, + new_perm: Option<NewPermission>, + ) -> InterpResult<'tcx> { + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; + let val = self.ecx.tb_retag_reference(&val, new_perm)?; + self.ecx.write_immediate(*val, place)?; + Ok(()) + } + } + impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>> + for RetagVisitor<'ecx, 'mir, 'tcx> + { + type V = PlaceTy<'tcx, Provenance>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> { + self.ecx + } + + fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx); + self.retag_ptr_inplace(place, new_perm) + } + + fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + // If this place is smaller than a pointer, we know that it can't contain any + // pointers we need to retag, so we can stop recursion early. + // This optimization is crucial for ZSTs, because they can contain way more fields + // than we can ever visit. + if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() { + return Ok(()); + } + + // Check the type of this value to see what to do with it (retag, or recurse). + match place.layout.ty.kind() { + &ty::Ref(_, pointee, mutability) => { + let new_perm = + NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx); + self.retag_ptr_inplace(place, new_perm)?; + } + ty::RawPtr(_) => { + // We definitely do *not* want to recurse into raw pointers -- wide raw + // pointers have fields, and for dyn Trait pointees those can have reference + // type! + // We also do not want to reborrow them. + } + ty::Adt(adt, _) if adt.is_box() => { + // Recurse for boxes, they require some tricky handling and will end up in `visit_box` above. + // (Yes this means we technically also recursively retag the allocator itself + // even if field retagging is not enabled. *shrug*) + self.walk_value(place)?; + } + _ => { + // Not a reference/pointer/box. Only recurse if configured appropriately. + let recurse = match self.retag_fields { + RetagFields::No => false, + RetagFields::Yes => true, + RetagFields::OnlyScalar => { + // Matching `ArgAbi::new` at the time of writing, only fields of + // `Scalar` and `ScalarPair` ABI are considered. + matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) + } + }; + if recurse { + self.walk_value(place)?; + } + } + } + + Ok(()) + } + } + } + + /// After a stack frame got pushed, retag the return place so that we are sure + /// it does not alias with anything. + /// + /// This is a HACK because there is nothing in MIR that would make the retag + /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>. + fn tb_retag_return_place(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + //this.debug_hint_location(); + let return_place = &this.frame().return_place; + if return_place.layout.is_zst() { + // There may not be any memory here, nothing to do. + return Ok(()); + } + // We need this to be in-memory to use tagged pointers. + let return_place = this.force_allocation(&return_place.clone())?; + + // We have to turn the place into a pointer to use the existing code. + // (The pointer type does not matter, so we use a raw pointer.) + let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); + // Reborrow it. With protection! That is part of the point. + // FIXME: do we truly want a 2phase borrow here? + let new_perm = Some(NewPermission { + initial_state: Permission::new_unique_2phase(/*freeze*/ false), + perform_read_access: true, + protector: Some(ProtectorKind::StrongProtector), + }); + let val = this.tb_retag_reference(&val, new_perm)?; + // And use reborrowed pointer for return place. + let return_place = this.ref_to_mplace(&val)?; + this.frame_mut().return_place = return_place.into(); + + Ok(()) + } + + /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. + fn tb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. + // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let alloc_extra = this.get_alloc_extra(alloc_id)?; + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); + alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag); + } + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { + // No tree borrows on these allocations. + } + } + Ok(()) + } + + /// Display the tree. + fn print_tree(&mut self, alloc_id: AllocId, show_unnamed: bool) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let tree_borrows = alloc_extra.borrow_tracker_tb().borrow(); + let borrow_tracker = &this.machine.borrow_tracker.as_ref().unwrap().borrow(); + tree_borrows.print_tree(&borrow_tracker.protected_tags, show_unnamed) + } + + /// Give a name to the pointer, usually the name it has in the source code (for debugging). + /// The name given is `name` and the pointer that receives it is the `nth_parent` + /// of `ptr` (with 0 representing `ptr` itself) + fn tb_give_pointer_debug_name( + &mut self, + ptr: Pointer<Option<Provenance>>, + nth_parent: u8, + name: &str, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (tag, alloc_id) = match ptr.provenance { + Some(Provenance::Concrete { tag, alloc_id }) => (tag, alloc_id), + _ => { + eprintln!("Can't give the name {name} to Wildcard pointer"); + return Ok(()); + } + }; + let alloc_extra = this.get_alloc_extra(alloc_id)?; + let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); + tree_borrows.give_pointer_debug_name(tag, nth_parent, name) + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs new file mode 100644 index 00000000000..04b8e1df576 --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -0,0 +1,307 @@ +use std::cmp::{Ordering, PartialOrd}; +use std::fmt; + +use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; +use crate::borrow_tracker::AccessKind; + +/// The activation states of a pointer +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum PermissionPriv { + /// represents: a local reference that has not yet been written to; + /// allows: child reads, foreign reads, foreign writes if type is freeze; + /// rejects: child writes (Active), foreign writes (Disabled, except if type is not freeze). + /// special case: behaves differently when protected to adhere more closely to noalias + Reserved { ty_is_freeze: bool }, + /// represents: a unique pointer; + /// allows: child reads, child writes; + /// rejects: foreign reads (Frozen), foreign writes (Disabled). + Active, + /// represents: a shared pointer; + /// allows: all read accesses; + /// rejects child writes (UB), foreign writes (Disabled). + Frozen, + /// represents: a dead pointer; + /// allows: all foreign accesses; + /// rejects: all child accesses (UB). + Disabled, +} +use PermissionPriv::*; + +impl PartialOrd for PermissionPriv { + /// PermissionPriv is ordered as follows: + /// - Reserved(_) < Active < Frozen < Disabled; + /// - different kinds of `Reserved` (with or without interior mutability) + /// are incomparable to each other. + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + use Ordering::*; + Some(match (self, other) { + (a, b) if a == b => Equal, + (Disabled, _) => Greater, + (_, Disabled) => Less, + (Frozen, _) => Greater, + (_, Frozen) => Less, + (Active, _) => Greater, + (_, Active) => Less, + (Reserved { .. }, Reserved { .. }) => return None, + }) + } +} + +/// This module controls how each permission individually reacts to an access. +/// Although these functions take `protected` as an argument, this is NOT because +/// we check protector violations here, but because some permissions behave differently +/// when protected. +mod transition { + use super::*; + /// A child node was read-accessed: UB on Disabled, noop on the rest. + fn child_read(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> { + Some(match state { + Disabled => return None, + // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read + // accesses, since the data is not being mutated. Hence the `{ .. }` + readable @ (Reserved { .. } | Active | Frozen) => readable, + }) + } + + /// A non-child node was read-accessed: noop on non-protected Reserved, advance to Frozen otherwise. + fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> { + use Option::*; + Some(match state { + // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read + // accesses, since the data is not being mutated. Hence the `{ .. }` + res @ Reserved { .. } if !protected => res, + Reserved { .. } => Frozen, // protected reserved + Active => Frozen, + non_writeable @ (Frozen | Disabled) => non_writeable, + }) + } + + /// A child node was write-accessed: `Reserved` must become `Active` to obtain + /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB. + fn child_write(state: PermissionPriv, _protected: bool) -> Option<PermissionPriv> { + Some(match state { + // A write always activates the 2-phase borrow, even with interior + // mutability + Reserved { .. } | Active => Active, + Frozen | Disabled => return None, + }) + } + + /// A non-child node was write-accessed: this makes everything `Disabled` except for + /// non-protected interior mutable `Reserved` which stay the same. + fn foreign_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> { + Some(match state { + cell @ Reserved { ty_is_freeze: false } if !protected => cell, + _ => Disabled, + }) + } + + /// Dispatch handler depending on the kind of access and its position. + pub(super) fn perform_access( + kind: AccessKind, + rel_pos: AccessRelatedness, + child: PermissionPriv, + protected: bool, + ) -> Option<PermissionPriv> { + match (kind, rel_pos.is_foreign()) { + (AccessKind::Write, true) => foreign_write(child, protected), + (AccessKind::Read, true) => foreign_read(child, protected), + (AccessKind::Write, false) => child_write(child, protected), + (AccessKind::Read, false) => child_read(child, protected), + } + } +} + +impl PermissionPriv { + /// Determines whether a transition that occured is compatible with the presence + /// of a Protector. This is not included in the `transition` functions because + /// it would distract from the few places where the transition is modified + /// because of a protector, but not forbidden. + fn protector_allows_transition(self, new: Self) -> bool { + match (self, new) { + _ if self == new => true, + // It is always a protector violation to not be readable anymore + (_, Disabled) => false, + // In the case of a `Reserved` under a protector, both transitions + // `Reserved => Active` and `Reserved => Frozen` can legitimately occur. + // The first is standard (Child Write), the second is for Foreign Writes + // on protected Reserved where we must ensure that the pointer is not + // written to in the future. + (Reserved { .. }, Active) | (Reserved { .. }, Frozen) => true, + // This pointer should have stayed writeable for the whole function + (Active, Frozen) => false, + _ => unreachable!("Transition from {self:?} to {new:?} should never be possible"), + } + } +} + +/// Public interface to the state machine that controls read-write permissions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Permission(PermissionPriv); + +impl fmt::Display for Permission { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self.0 { + PermissionPriv::Reserved { .. } => "Reserved", + PermissionPriv::Active => "Active", + PermissionPriv::Frozen => "Frozen", + PermissionPriv::Disabled => "Disabled", + } + ) + } +} + +impl Permission { + /// Default initial permission of the root of a new tree. + pub fn new_root() -> Self { + Self(Active) + } + + /// Default initial permission of a reborrowed mutable reference. + pub fn new_unique_2phase(ty_is_freeze: bool) -> Self { + Self(Reserved { ty_is_freeze }) + } + + /// Default initial permission of a reborrowed shared reference + pub fn new_frozen() -> Self { + Self(Frozen) + } + + /// Pretty-printing. Needs to be here and not in diagnostics.rs + /// because `Self` is private. + pub fn short_name(self) -> &'static str { + // Make sure there are all of the same length as each other + // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise + // alignment will be incorrect. + match self.0 { + Reserved { ty_is_freeze: true } => "Res", + Reserved { ty_is_freeze: false } => "Re*", + Active => "Act", + Frozen => "Frz", + Disabled => "Dis", + } + } + + /// Check that there are no complaints from a possible protector. + /// + /// Note: this is not in charge of checking that there *is* a protector, + /// it should be used as + /// ``` + /// let no_protector_error = if is_protected(tag) { + /// old_perm.protector_allows_transition(new_perm) + /// }; + /// ``` + pub fn protector_allows_transition(self, new: Self) -> bool { + self.0.protector_allows_transition(new.0) + } + + /// Apply the transition to the inner PermissionPriv. + pub fn perform_access( + kind: AccessKind, + rel_pos: AccessRelatedness, + old_perm: Self, + protected: bool, + ) -> Option<Self> { + let old_state = old_perm.0; + transition::perform_access(kind, rel_pos, old_state, protected).map(Self) + } +} + +#[cfg(test)] +mod propagation_optimization_checks { + pub use super::*; + + mod util { + pub use super::*; + impl PermissionPriv { + /// Enumerate all states + pub fn all() -> impl Iterator<Item = PermissionPriv> { + vec![ + Active, + Reserved { ty_is_freeze: true }, + Reserved { ty_is_freeze: false }, + Frozen, + Disabled, + ] + .into_iter() + } + } + + impl AccessKind { + /// Enumerate all AccessKind. + pub fn all() -> impl Iterator<Item = AccessKind> { + use AccessKind::*; + [Read, Write].into_iter() + } + } + + impl AccessRelatedness { + /// Enumerate all relative positions + pub fn all() -> impl Iterator<Item = AccessRelatedness> { + use AccessRelatedness::*; + [This, StrictChildAccess, AncestorAccess, DistantAccess].into_iter() + } + } + } + + #[test] + // For any kind of access, if we do it twice the second should be a no-op. + // Even if the protector has disappeared. + fn all_transitions_idempotent() { + use transition::*; + for old in PermissionPriv::all() { + for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] { + for access in AccessKind::all() { + for rel_pos in AccessRelatedness::all() { + if let Some(new) = perform_access(access, rel_pos, old, old_protected) { + assert_eq!( + new, + perform_access(access, rel_pos, new, new_protected).unwrap() + ); + } + } + } + } + } + } + + #[test] + fn foreign_read_is_noop_after_write() { + use transition::*; + let old_access = AccessKind::Write; + let new_access = AccessKind::Read; + for old in PermissionPriv::all() { + for (old_protected, new_protected) in [(true, true), (true, false), (false, false)] { + for rel_pos in AccessRelatedness::all().filter(|rel| rel.is_foreign()) { + if let Some(new) = perform_access(old_access, rel_pos, old, old_protected) { + assert_eq!( + new, + perform_access(new_access, rel_pos, new, new_protected).unwrap() + ); + } + } + } + } + } + + #[test] + // Check that all transitions are consistent with the order on PermissionPriv, + // i.e. Reserved -> Active -> Frozen -> Disabled + fn access_transitions_progress_increasing() { + use transition::*; + for old in PermissionPriv::all() { + for protected in [true, false] { + for access in AccessKind::all() { + for rel_pos in AccessRelatedness::all() { + if let Some(new) = perform_access(access, rel_pos, old, protected) { + assert!(old <= new); + } + } + } + } + } + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs new file mode 100644 index 00000000000..86416a0eb1b --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -0,0 +1,554 @@ +//! In this file we handle the "Tree" part of Tree Borrows, i.e. all tree +//! traversal functions, optimizations to trim branches, and keeping track of +//! the relative position of the access to each node being updated. This of course +//! also includes the definition of the tree structure. +//! +//! Functions here manipulate permissions but are oblivious to them: as +//! the internals of `Permission` are private, the update process is a black +//! box. All we need to know here are +//! - the fact that updates depend only on the old state, the status of protectors, +//! and the relative position of the access; +//! - idempotency properties asserted in `perms.rs` (for optimizations) + +use smallvec::SmallVec; + +use rustc_const_eval::interpret::InterpResult; +use rustc_data_structures::fx::FxHashSet; +use rustc_target::abi::Size; + +use crate::borrow_tracker::tree_borrows::{ + diagnostics::{NodeDebugInfo, TbError, TransitionError}, + unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap}, + Permission, +}; +use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind}; +use crate::*; + +/// Data for a single *location*. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) struct LocationState { + /// This pointer's current permission + permission: Permission, + /// A location is initialized when it is child accessed for the first time, + /// and it then stays initialized forever. + /// Before initialization we still apply some preemptive transitions on + /// `permission` to know what to do in case it ever gets initialized, + /// but these can never cause any immediate UB. There can however be UB + /// the moment we attempt to initalize (i.e. child-access) because some + /// foreign access done between the creation and the initialization is + /// incompatible with child accesses. + initialized: bool, + /// Strongest foreign access whose effects have already been applied to + /// this node and all its children since the last child access. + /// This is `None` if the most recent access is a child access, + /// `Some(Write)` if at least one foreign write access has been applied + /// since the previous child access, and `Some(Read)` if at least one + /// foreign read and no foreign write have occurred since the last child access. + latest_foreign_access: Option<AccessKind>, +} + +impl LocationState { + /// Default initial state has never been accessed and has been subjected to no + /// foreign access. + fn new(permission: Permission) -> Self { + Self { permission, initialized: false, latest_foreign_access: None } + } + + /// Record that this location was accessed through a child pointer by + /// marking it as initialized + fn with_access(mut self) -> Self { + self.initialized = true; + self + } + + pub fn is_initialized(&self) -> bool { + self.initialized + } + + pub fn permission(&self) -> Permission { + self.permission + } +} + +/// Tree structure with both parents and children since we want to be +/// able to traverse the tree efficiently in both directions. +#[derive(Clone, Debug)] +pub struct Tree { + /// Mapping from tags to keys. The key obtained can then be used in + /// any of the `UniValMap` relative to this allocation, i.e. both the + /// `nodes` and `rperms` of the same `Tree`. + /// The parent-child relationship in `Node` is encoded in terms of these same + /// keys, so traversing the entire tree needs exactly one access to + /// `tag_mapping`. + pub(super) tag_mapping: UniKeyMap<BorTag>, + /// All nodes of this tree. + pub(super) nodes: UniValMap<Node>, + /// Maps a tag and a location to a perm, with possible lazy + /// initialization. + /// + /// NOTE: not all tags registered in `nodes` are necessarily in all + /// ranges of `rperms`, because `rperms` is in part lazily initialized. + /// Just because `nodes.get(key)` is `Some(_)` does not mean you can safely + /// `unwrap` any `perm.get(key)`. + /// + /// We do uphold the fact that `keys(perms)` is a subset of `keys(nodes)` + pub(super) rperms: RangeMap<UniValMap<LocationState>>, + /// The index of the root node. + pub(super) root: UniIndex, +} + +/// A node in the borrow tree. Each node is uniquely identified by a tag via +/// the `nodes` map of `Tree`. +#[derive(Clone, Debug)] +pub(super) struct Node { + /// The tag of this node. + pub tag: BorTag, + /// All tags except the root have a parent tag. + pub parent: Option<UniIndex>, + /// If the pointer was reborrowed, it has children. + // FIXME: bench to compare this to FxHashSet and to other SmallVec sizes + pub children: SmallVec<[UniIndex; 4]>, + /// Either `Reserved` or `Frozen`, the permission this tag will be lazily initialized + /// to on the first access. + default_initial_perm: Permission, + /// Some extra information useful only for debugging purposes + pub debug_info: NodeDebugInfo, +} + +/// Data given to the transition function +struct NodeAppArgs<'node> { + /// Node on which the transition is currently being applied + node: &'node Node, + /// Mutable access to its permissions + perm: UniEntry<'node, LocationState>, + /// Relative position of the access + rel_pos: AccessRelatedness, +} +/// Data given to the error handler +struct ErrHandlerArgs<'node, InErr> { + /// Kind of error that occurred + error_kind: InErr, + /// Tag that triggered the error (not the tag that was accessed, + /// rather the parent tag that had insufficient permissions or the + /// non-parent tag that had a protector). + faulty_tag: &'node NodeDebugInfo, +} +/// Internal contents of `Tree` with the minimum of mutable access for +/// the purposes of the tree traversal functions: the permissions (`perms`) can be +/// updated but not the tree structure (`tag_mapping` and `nodes`) +struct TreeVisitor<'tree> { + tag_mapping: &'tree UniKeyMap<BorTag>, + nodes: &'tree UniValMap<Node>, + perms: &'tree mut UniValMap<LocationState>, +} + +/// Whether to continue exploring the children recursively or not. +enum ContinueTraversal { + Recurse, + SkipChildren, +} + +impl<'tree> TreeVisitor<'tree> { + // Applies `f_propagate` to every vertex of the tree top-down in the following order: first + // all ancestors of `start`, then `start` itself, then children of `start`, then the rest. + // This ensures that errors are triggered in the following order + // - first invalid accesses with insufficient permissions, closest to the root first, + // - then protector violations, closest to `start` first. + // + // `f_propagate` should follow the following format: for a given `Node` it updates its + // `Permission` depending on the position relative to `start` (given by an + // `AccessRelatedness`). + // It outputs whether the tree traversal for this subree should continue or not. + fn traverse_parents_this_children_others<InnErr, OutErr>( + mut self, + start: BorTag, + f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>, + err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr, + ) -> Result<(), OutErr> +where { + struct TreeVisitAux<NodeApp, ErrHandler> { + f_propagate: NodeApp, + err_builder: ErrHandler, + stack: Vec<(UniIndex, AccessRelatedness)>, + } + impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitAux<NodeApp, ErrHandler> + where + NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>, + ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr, + { + fn pop(&mut self) -> Option<(UniIndex, AccessRelatedness)> { + self.stack.pop() + } + + /// Apply the function to the current `tag`, and push its children + /// to the stack of future tags to visit. + fn exec_and_visit( + &mut self, + this: &mut TreeVisitor<'_>, + tag: UniIndex, + exclude: Option<UniIndex>, + rel_pos: AccessRelatedness, + ) -> Result<(), OutErr> { + // 1. apply the propagation function + let node = this.nodes.get(tag).unwrap(); + let recurse = + (self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(tag), rel_pos }) + .map_err(|error_kind| { + (self.err_builder)(ErrHandlerArgs { + error_kind, + faulty_tag: &node.debug_info, + }) + })?; + // 2. add the children to the stack for future traversal + if matches!(recurse, ContinueTraversal::Recurse) { + let child_rel = rel_pos.for_child(); + for &child in node.children.iter() { + // some child might be excluded from here and handled separately + if Some(child) != exclude { + self.stack.push((child, child_rel)); + } + } + } + Ok(()) + } + } + + let start_idx = self.tag_mapping.get(&start).unwrap(); + let mut stack = TreeVisitAux { f_propagate, err_builder, stack: Vec::new() }; + { + let mut path_ascend = Vec::new(); + // First climb to the root while recording the path + let mut curr = start_idx; + while let Some(ancestor) = self.nodes.get(curr).unwrap().parent { + path_ascend.push((ancestor, curr)); + curr = ancestor; + } + // Then descend: + // - execute f_propagate on each node + // - record children in visit + while let Some((ancestor, next_in_path)) = path_ascend.pop() { + // Explore ancestors in descending order. + // `next_in_path` is excluded from the recursion because it + // will be the `ancestor` of the next iteration. + // It also needs a different `AccessRelatedness` than the other + // children of `ancestor`. + stack.exec_and_visit( + &mut self, + ancestor, + Some(next_in_path), + AccessRelatedness::StrictChildAccess, + )?; + } + }; + // All (potentially zero) ancestors have been explored, call f_propagate on start + stack.exec_and_visit(&mut self, start_idx, None, AccessRelatedness::This)?; + // up to this point we have never popped from `stack`, hence if the + // path to the root is `root = p(n) <- p(n-1)... <- p(1) <- p(0) = start` + // then now `stack` contains + // `[<children(p(n)) except p(n-1)> ... <children(p(1)) except p(0)> <children(p(0))>]`, + // all of which are for now unexplored. + // This is the starting point of a standard DFS which will thus + // explore all non-ancestors of `start` in the following order: + // - all descendants of `start`; + // - then the unexplored descendants of `parent(start)`; + // ... + // - until finally the unexplored descendants of `root`. + while let Some((tag, rel_pos)) = stack.pop() { + stack.exec_and_visit(&mut self, tag, None, rel_pos)?; + } + Ok(()) + } +} + +impl Tree { + /// Create a new tree, with only a root pointer. + pub fn new(root_tag: BorTag, size: Size) -> Self { + let root_perm = Permission::new_root(); + let mut tag_mapping = UniKeyMap::default(); + let root_idx = tag_mapping.insert(root_tag); + let nodes = { + let mut nodes = UniValMap::<Node>::default(); + nodes.insert( + root_idx, + Node { + tag: root_tag, + parent: None, + children: SmallVec::default(), + default_initial_perm: root_perm, + debug_info: NodeDebugInfo::new(root_tag), + }, + ); + nodes + }; + let rperms = { + let mut perms = UniValMap::default(); + perms.insert(root_idx, LocationState::new(root_perm).with_access()); + RangeMap::new(size, perms) + }; + Self { root: root_idx, nodes, rperms, tag_mapping } + } +} + +impl<'tcx> Tree { + /// Insert a new tag in the tree + pub fn new_child( + &mut self, + parent_tag: BorTag, + new_tag: BorTag, + default_initial_perm: Permission, + range: AllocRange, + ) -> InterpResult<'tcx> { + assert!(!self.tag_mapping.contains_key(&new_tag)); + let idx = self.tag_mapping.insert(new_tag); + let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); + // Create the node + self.nodes.insert( + idx, + Node { + tag: new_tag, + parent: Some(parent_idx), + children: SmallVec::default(), + default_initial_perm, + debug_info: NodeDebugInfo::new(new_tag), + }, + ); + // Register new_tag as a child of parent_tag + self.nodes.get_mut(parent_idx).unwrap().children.push(idx); + // Initialize perms + let perm = LocationState::new(default_initial_perm).with_access(); + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + perms.insert(idx, perm); + } + Ok(()) + } + + /// Deallocation requires + /// - a pointer that permits write accesses + /// - the absence of Strong Protectors anywhere in the allocation + pub fn dealloc( + &mut self, + tag: BorTag, + range: AllocRange, + global: &GlobalState, + ) -> InterpResult<'tcx> { + self.perform_access(AccessKind::Write, tag, range, global)?; + let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info; + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms } + .traverse_parents_this_children_others( + tag, + |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> { + let NodeAppArgs { node, .. } = args; + if global.borrow().protected_tags.get(&node.tag) + == Some(&ProtectorKind::StrongProtector) + { + Err(TransitionError::ProtectedDealloc) + } else { + Ok(ContinueTraversal::Recurse) + } + }, + |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> { + let ErrHandlerArgs { error_kind, faulty_tag } = args; + TbError { + faulty_tag, + access_kind: AccessKind::Write, + error_kind, + tag_of_access: access_info, + } + .build() + }, + )?; + } + Ok(()) + } + + /// Maps the following propagation procedure to each range: + /// - initialize if needed; + /// - compute new state after transition; + /// - check that there is no protector that would forbid this; + /// - record this specific location as accessed. + pub fn perform_access( + &mut self, + access_kind: AccessKind, + tag: BorTag, + range: AllocRange, + global: &GlobalState, + ) -> InterpResult<'tcx> { + let access_info = &self.nodes.get(self.tag_mapping.get(&tag).unwrap()).unwrap().debug_info; + for (_range, perms) in self.rperms.iter_mut(range.start, range.size) { + TreeVisitor { nodes: &self.nodes, tag_mapping: &self.tag_mapping, perms } + .traverse_parents_this_children_others( + tag, + |args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> { + let NodeAppArgs { node, mut perm, rel_pos } = args; + + let old_state = + perm.or_insert_with(|| LocationState::new(node.default_initial_perm)); + + // Optimize the tree traversal. + // The optimization here consists of observing thanks to the tests + // `foreign_read_is_noop_after_write` and `all_transitions_idempotent` + // that if we apply twice in a row the effects of a foreign access + // we can skip some branches. + // "two foreign accesses in a row" occurs when `perm.latest_foreign_access` is `Some(_)` + // AND the `rel_pos` of the current access corresponds to a foreign access. + if rel_pos.is_foreign() { + let new_access_noop = + match (old_state.latest_foreign_access, access_kind) { + // Previously applied transition makes the new one a guaranteed + // noop in the two following cases: + // (1) justified by `foreign_read_is_noop_after_write` + (Some(AccessKind::Write), AccessKind::Read) => true, + // (2) justified by `all_transitions_idempotent` + (Some(old), new) if old == new => true, + // In all other cases there has been a recent enough + // child access that the effects of the new foreign access + // need to be applied to this subtree. + _ => false, + }; + if new_access_noop { + // Abort traversal if the new transition is indeed guaranteed + // to be noop. + return Ok(ContinueTraversal::SkipChildren); + } else { + // Otherwise propagate this time, and also record the + // access that just occurred so that we can skip the propagation + // next time. + old_state.latest_foreign_access = Some(access_kind); + } + } else { + // A child access occurred, this breaks the streak of "two foreign + // accesses in a row" and we reset this field. + old_state.latest_foreign_access = None; + } + + let old_perm = old_state.permission; + let protected = global.borrow().protected_tags.contains_key(&node.tag); + let new_perm = + Permission::perform_access(access_kind, rel_pos, old_perm, protected) + .ok_or(TransitionError::ChildAccessForbidden(old_perm))?; + if protected + // Can't trigger Protector on uninitialized locations + && old_state.initialized + && !old_perm.protector_allows_transition(new_perm) + { + return Err(TransitionError::ProtectedTransition(old_perm, new_perm)); + } + old_state.permission = new_perm; + old_state.initialized |= !rel_pos.is_foreign(); + Ok(ContinueTraversal::Recurse) + }, + |args: ErrHandlerArgs<'_, TransitionError>| -> InterpErrorInfo<'tcx> { + let ErrHandlerArgs { error_kind, faulty_tag } = args; + TbError { faulty_tag, access_kind, error_kind, tag_of_access: access_info } + .build() + }, + )?; + } + Ok(()) + } +} + +/// Integration with the BorTag garbage collector +impl Tree { + pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<BorTag>) { + assert!(self.keep_only_needed(self.root, live_tags)); // root can't be removed + } + + /// Traverses the entire tree looking for useless tags. + /// Returns true iff the tag it was called on is still live or has live children, + /// and removes from the tree all tags that have no live children. + /// + /// NOTE: This leaves in the middle of the tree tags that are unreachable but have + /// reachable children. There is a potential for compacting the tree by reassigning + /// children of dead tags to the nearest live parent, but it must be done with care + /// not to remove UB. + /// + /// Example: Consider the tree `root - parent - child`, with `parent: Frozen` and + /// `child: Reserved`. This tree can exist. If we blindly delete `parent` and reassign + /// `child` to be a direct child of `root` then Writes to `child` are now permitted + /// whereas they were not when `parent` was still there. + fn keep_only_needed(&mut self, idx: UniIndex, live: &FxHashSet<BorTag>) -> bool { + let node = self.nodes.get(idx).unwrap(); + // FIXME: this function does a lot of cloning, a 2-pass approach is possibly + // more efficient. It could consist of + // 1. traverse the Tree, collect all useless tags in a Vec + // 2. traverse the Vec, remove all tags previously selected + // Bench it. + let children: SmallVec<_> = node + .children + .clone() + .into_iter() + .filter(|child| self.keep_only_needed(*child, live)) + .collect(); + let no_children = children.is_empty(); + let node = self.nodes.get_mut(idx).unwrap(); + node.children = children; + if !live.contains(&node.tag) && no_children { + // All of the children and this node are unreachable, delete this tag + // from the tree (the children have already been deleted by recursive + // calls). + // Due to the API of UniMap we must absolutely call + // `UniValMap::remove` for the key of this tag on *all* maps that used it + // (which are `self.nodes` and every range of `self.rperms`) + // before we can safely apply `UniValMap::forget` to truly remove + // the tag from the mapping. + let tag = node.tag; + self.nodes.remove(idx); + for perms in self.rperms.iter_mut_all() { + perms.remove(idx); + } + self.tag_mapping.remove(&tag); + // The tag has been deleted, inform the caller + false + } else { + // The tag is still live or has live children, it must be kept + true + } + } +} + +impl VisitTags for Tree { + fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + // To ensure that the root never gets removed, we visit it + // (the `root` node of `Tree` is not an `Option<_>`) + visit(self.nodes.get(self.root).unwrap().tag) + } +} + +/// Relative position of the access +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AccessRelatedness { + /// The accessed pointer is the current one + This, + /// The accessed pointer is a (transitive) child of the current one. + // Current pointer is excluded (unlike in some other places of this module + // where "child" is inclusive). + StrictChildAccess, + /// The accessed pointer is a (transitive) parent of the current one. + // Current pointer is excluded. + AncestorAccess, + /// The accessed pointer is neither of the above. + // It's a cousin/uncle/etc., something in a side branch. + // FIXME: find a better name ? + DistantAccess, +} + +impl AccessRelatedness { + /// Check that access is either Ancestor or Distant, i.e. not + /// a transitive child (initial pointer included). + pub fn is_foreign(self) -> bool { + matches!(self, AccessRelatedness::AncestorAccess | AccessRelatedness::DistantAccess) + } + + /// Given the AccessRelatedness for the parent node, compute the AccessRelatedness + /// for the child node. This function assumes that we propagate away from the initial + /// access. + pub fn for_child(self) -> Self { + use AccessRelatedness::*; + match self { + AncestorAccess | This => AncestorAccess, + StrictChildAccess | DistantAccess => DistantAccess, + } + } +} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs new file mode 100644 index 00000000000..c1d452ca89e --- /dev/null +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs @@ -0,0 +1,304 @@ +//! This module implements the `UniMap`, which is a way to get efficient mappings +//! optimized for the setting of `tree_borrows/tree.rs`. +//! +//! A `UniKeyMap<K>` is a (slow) mapping from `K` to `UniIndex`, +//! and `UniValMap<V>` is a (fast) mapping from `UniIndex` to `V`. +//! Thus a pair `(UniKeyMap<K>, UniValMap<V>)` acts as a virtual `HashMap<K, V>`. +//! +//! Because of the asymmetry in access time, the use-case for `UniMap` is the following: +//! a tuple `(UniKeyMap<K>, Vec<UniValMap<V>>)` is much more efficient than +//! the equivalent `Vec<HashMap<K, V>>` it represents if all maps have similar +//! sets of keys. + +#![allow(dead_code)] + +use std::hash::Hash; + +use rustc_data_structures::fx::FxHashMap; + +/// Intermediate key between a UniKeyMap and a UniValMap. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UniIndex { + idx: u32, +} + +/// From K to UniIndex +#[derive(Debug, Clone, Default)] +pub struct UniKeyMap<K> { + /// Underlying map that does all the hard work. + /// Key invariant: the contents of `deassigned` are disjoint from the + /// keys of `mapping`, and together they form the set of contiguous integers + /// `0 .. (mapping.len() + deassigned.len())`. + mapping: FxHashMap<K, u32>, + /// Indexes that can be reused: memory gain when the map gets sparse + /// due to many deletions. + deassigned: Vec<u32>, +} + +/// From UniIndex to V +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UniValMap<V> { + /// The mapping data. Thanks to Vec we get both fast accesses, and + /// a memory-optimal representation if there are few deletions. + data: Vec<Option<V>>, +} + +impl<V> Default for UniValMap<V> { + fn default() -> Self { + Self { data: Vec::default() } + } +} + +impl<K> UniKeyMap<K> +where + K: Hash + Eq, +{ + /// How many keys/index pairs are currently active. + pub fn len(&self) -> usize { + self.mapping.len() + } + + /// Whether this key has an associated index or not. + pub fn contains_key(&self, key: &K) -> bool { + self.mapping.contains_key(key) + } + + /// Assign this key to a new index. Panics if the key is already assigned, + /// use `get_or_insert` for a version that instead returns the existing + /// assignment. + #[track_caller] + pub fn insert(&mut self, key: K) -> UniIndex { + // We want an unused index. First we attempt to find one from `deassigned`, + // and if `deassigned` is empty we generate a fresh index. + let idx = self.deassigned.pop().unwrap_or_else(|| { + // `deassigned` is empty, so all keys in use are already in `mapping`. + // The next available key is `mapping.len()`. + self.mapping.len().try_into().expect("UniMap ran out of useable keys") + }); + if self.mapping.insert(key, idx).is_some() { + panic!( + "This key is already assigned to a different index; either use `get_or_insert` instead if you care about this data, or first call `remove` to undo the preexisting assignment." + ); + }; + UniIndex { idx } + } + + /// If it exists, the index this key maps to. + pub fn get(&self, key: &K) -> Option<UniIndex> { + self.mapping.get(key).map(|&idx| UniIndex { idx }) + } + + /// Either get a previously existing entry, or create a new one if it + /// is not yet present. + pub fn get_or_insert(&mut self, key: K) -> UniIndex { + self.get(&key).unwrap_or_else(|| self.insert(key)) + } + + /// Return whatever index this key was using to the deassigned pool. + /// + /// Note: calling this function can be dangerous. If the index still exists + /// somewhere in a `UniValMap` and is reassigned by the `UniKeyMap` then + /// it will inherit the old value of a completely unrelated key. + /// If you `UniKeyMap::remove` a key you should make sure to also `UniValMap::remove` + /// the associated `UniIndex` from ALL `UniValMap`s. + /// + /// Example of such behavior: + /// ``` + /// let mut keymap = UniKeyMap::<char>::default(); + /// let mut valmap = UniValMap::<char>::default(); + /// // Insert 'a' -> _ -> 'A' + /// let idx_a = keymap.insert('a'); + /// valmap.insert(idx_a, 'A'); + /// // Remove 'a' -> _, but forget to remove _ -> 'A' + /// keymap.remove(&'a'); + /// // valmap.remove(idx_a); // If we uncomment this line the issue is fixed + /// // Insert 'b' -> _ + /// let idx_b = keymap.insert('b'); + /// let val_b = valmap.get(idx_b); + /// assert_eq!(val_b, Some('A')); // Oh no + /// // assert_eq!(val_b, None); // This is what we would have expected + /// ``` + pub fn remove(&mut self, key: &K) { + if let Some(idx) = self.mapping.remove(key) { + self.deassigned.push(idx); + } + } +} + +impl<V> UniValMap<V> { + /// Whether this index has an associated value. + pub fn contains_idx(&self, idx: UniIndex) -> bool { + self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some() + } + + /// Reserve enough space to insert the value at the right index. + fn extend_to_length(&mut self, len: usize) { + if len > self.data.len() { + let nb = len - self.data.len(); + self.data.reserve(nb); + for _ in 0..nb { + self.data.push(None); + } + } + } + + /// Assign a value to the index. Permanently overwrites any previous value. + pub fn insert(&mut self, idx: UniIndex, val: V) { + self.extend_to_length(idx.idx as usize + 1); + self.data[idx.idx as usize] = Some(val) + } + + /// Get the value at this index, if it exists. + pub fn get(&self, idx: UniIndex) -> Option<&V> { + self.data.get(idx.idx as usize).and_then(Option::as_ref) + } + + /// Get the value at this index mutably, if it exists. + pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> { + self.data.get_mut(idx.idx as usize).and_then(Option::as_mut) + } + + /// Delete any value associated with this index. Ok even if the index + /// has no associated value. + pub fn remove(&mut self, idx: UniIndex) { + if idx.idx as usize >= self.data.len() { + return; + } + self.data[idx.idx as usize] = None; + } +} + +/// An access to a single value of the map. +pub struct UniEntry<'a, V> { + inner: &'a mut Option<V>, +} + +impl<'a, V> UniValMap<V> { + /// Get a wrapper around a mutable access to the value corresponding to `idx`. + pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> { + self.extend_to_length(idx.idx as usize + 1); + UniEntry { inner: &mut self.data[idx.idx as usize] } + } +} + +impl<'a, V> UniEntry<'a, V> { + /// Insert in the map and get the value. + pub fn or_insert_with<F>(&mut self, default: F) -> &mut V + where + F: FnOnce() -> V, + { + if self.inner.is_none() { + *self.inner = Some(default()); + } + self.inner.as_mut().unwrap() + } +} + +mod tests { + use super::*; + + #[test] + fn extend_to_length() { + let mut km = UniValMap::<char>::default(); + km.extend_to_length(10); + assert!(km.data.len() == 10); + km.extend_to_length(0); + assert!(km.data.len() == 10); + km.extend_to_length(10); + assert!(km.data.len() == 10); + km.extend_to_length(11); + assert!(km.data.len() == 11); + } + + #[derive(Default)] + struct MapWitness<K, V> { + key: UniKeyMap<K>, + val: UniValMap<V>, + map: FxHashMap<K, V>, + } + + impl<K, V> MapWitness<K, V> + where + K: Copy + Hash + Eq, + V: Copy + Eq + std::fmt::Debug, + { + fn insert(&mut self, k: K, v: V) { + // UniMap + let i = self.key.get_or_insert(k); + self.val.insert(i, v); + // HashMap + self.map.insert(k, v); + // Consistency: nothing to check + } + + fn get(&self, k: &K) { + // UniMap + let v1 = self.key.get(k).and_then(|i| self.val.get(i)); + // HashMap + let v2 = self.map.get(k); + // Consistency + assert_eq!(v1, v2); + } + + fn get_mut(&mut self, k: &K) { + // UniMap + let v1 = self.key.get(k).and_then(|i| self.val.get_mut(i)); + // HashMap + let v2 = self.map.get_mut(k); + // Consistency + assert_eq!(v1, v2); + } + fn remove(&mut self, k: &K) { + // UniMap + if let Some(i) = self.key.get(k) { + self.val.remove(i); + } + self.key.remove(k); + // HashMap + self.map.remove(k); + // Consistency: nothing to check + } + } + + #[test] + fn consistency_small() { + let mut m = MapWitness::<u64, char>::default(); + m.insert(1, 'a'); + m.insert(2, 'b'); + m.get(&1); + m.get_mut(&2); + m.remove(&2); + m.insert(1, 'c'); + m.get(&1); + m.insert(3, 'd'); + m.insert(4, 'e'); + m.insert(4, 'f'); + m.get(&2); + m.get(&3); + m.get(&4); + m.get(&5); + m.remove(&100); + m.get_mut(&100); + m.get(&100); + } + + #[test] + fn consistency_large() { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + let mut hasher = DefaultHasher::new(); + let mut map = MapWitness::<u64, u64>::default(); + for i in 0..1000 { + i.hash(&mut hasher); + let rng = hasher.finish(); + let op = rng % 3 == 0; + let key = (rng / 2) % 50; + let val = (rng / 100) % 1000; + if op { + map.insert(key, val); + } else { + map.get(&key); + } + } + } +} diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 035c0e64233..3c13118122c 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -22,6 +22,10 @@ pub enum TerminationInfo { help: Option<String>, history: Option<TagHistory>, }, + TreeBorrowsUb { + msg: String, + // FIXME: incomplete + }, Int2PtrWithStrictProvenance, Deadlock, MultipleSymbolDefinitions { @@ -61,6 +65,7 @@ impl fmt::Display for TerminationInfo { "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" ), StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), + TreeBorrowsUb { msg } => write!(f, "{msg}"), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), @@ -184,7 +189,8 @@ pub fn report_error<'tcx, 'mir>( Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance => Some("unsupported operation"), - StackedBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), + StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } => + Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; @@ -212,6 +218,12 @@ pub fn report_error<'tcx, 'mir>( } } helps + }, + TreeBorrowsUb { .. } => { + let helps = vec![ + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")), + ]; + helps } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 8443e907938..a32b18595b5 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -87,7 +87,7 @@ pub struct MiriConfig { pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. pub validate: bool, - /// Determines if Stacked Borrows is enabled. + /// Determines if Stacked Borrows or Tree Borrows is enabled. pub borrow_tracker: Option<BorrowTrackerMethod>, /// Controls alignment checking. pub check_alignment: AlignmentCheck, @@ -134,7 +134,7 @@ pub struct MiriConfig { pub preemption_rate: f64, /// Report the current instruction being executed every N basic blocks. pub report_progress: Option<u32>, - /// Whether Stacked Borrows retagging should recurse into fields of datatypes. + /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes. pub retag_fields: RetagFields, /// The location of a shared object file to load when calling external functions /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ed3dd741a8b..21a413002d0 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1,5 +1,6 @@ pub mod convert; +use std::any::Any; use std::cmp; use std::iter; use std::num::NonZeroUsize; @@ -23,7 +24,23 @@ use rand::RngCore; use crate::*; -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +/// A trait to work around not having trait object upcasting: +/// Add `AsAny` as supertrait and your trait objects can be turned into `&dyn Any` on which you can +/// then call `downcast`. +pub trait AsAny: Any { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} +impl<T: Any> AsAny for T { + #[inline(always)] + fn as_any(&self) -> &dyn Any { + self + } + #[inline(always)] + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} // This mapping should match `decode_error_kind` in // <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/mod.rs>. @@ -119,6 +136,7 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) } } +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Checks if the given crate/module exists. fn have_module(&self, path: &[&str]) -> bool { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index f64f216520f..01d0f01d319 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -9,6 +9,7 @@ #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] #![feature(is_terminal)] +#![feature(round_ties_even)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -94,6 +95,7 @@ pub use crate::shims::EvalContextExt as _; pub use crate::borrow_tracker::stacked_borrows::{ EvalContextExt as _, Item, Permission, Stack, Stacks, }; +pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree}; pub use crate::borrow_tracker::{ BorTag, BorrowTrackerMethod, CallId, EvalContextExt as _, RetagFields, }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 969c81f7e32..c4baeb2a73b 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -38,7 +38,7 @@ pub const SIGRTMAX: i32 = 42; /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { - /// Extra data for Stacked Borrows. + /// Extra data for the Borrow Tracker. pub borrow_tracker: Option<borrow_tracker::FrameState>, /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` @@ -146,7 +146,7 @@ impl fmt::Display for MiriMemoryKind { pub enum Provenance { Concrete { alloc_id: AllocId, - /// Stacked Borrows tag. + /// Borrow Tracker tag. tag: BorTag, }, Wildcard, @@ -195,7 +195,7 @@ impl fmt::Debug for Provenance { } else { write!(f, "[{alloc_id:?}]")?; } - // Print Stacked Borrows tag. + // Print Borrow Tracker tag. write!(f, "{tag:?}")?; } Provenance::Wildcard => { @@ -822,7 +822,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { } #[inline(always)] - fn ignore_checkable_overflow_assertions(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { + fn ignore_optional_overflow_checks(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { !ecx.tcx.sess.overflow_checks() } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 03275ed4ed1..73439133af2 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -232,6 +232,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } + /// Read bytes from a `(ptr, len)` argument + fn read_byte_slice<'i>(&'i self, bytes: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, &'i [u8]> + where + 'mir: 'i, + { + let this = self.eval_context_ref(); + let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair(); + let ptr = ptr.to_pointer(this)?; + let len = len.to_target_usize(this)?; + let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + Ok(bytes) + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. /// Returns Ok(None) if the foreign item was completely handled @@ -427,13 +440,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { })?; this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } - "miri_print_borrow_stacks" => { - let [id] = this.check_shim(abi, Abi::Rust, link_name, args)?; + "miri_print_borrow_state" => { + let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?; let id = this.read_scalar(id)?.to_u64()?; + let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZeroU64::new(id) { - this.print_stacks(AllocId(id))?; + this.print_borrow_state(AllocId(id), show_unnamed)?; } } + "miri_pointer_name" => { + // This associates a name to a tag. Very useful for debugging, and also makes + // tests more strict. + let [ptr, nth_parent, name] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; + let name = this.read_byte_slice(name)?; + // We must make `name` owned because we need to + // end the shared borrow from `read_byte_slice` before we can + // start the mutable borrow for `give_pointer_debug_name`. + let name = String::from_utf8_lossy(name).into_owned(); + this.give_pointer_debug_name(ptr, nth_parent, &name)?; + } "miri_static_root" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; @@ -487,12 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Writes some bytes to the interpreter's stdout/stderr. See the // README for details. "miri_write_to_stdout" | "miri_write_to_stderr" => { - let [bytes] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let (ptr, len) = this.read_immediate(bytes)?.to_scalar_pair(); - let ptr = ptr.to_pointer(this)?; - let len = len.to_target_usize(this)?; - let msg = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - + let [msg] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let msg = this.read_byte_slice(msg)?; // Note: we're ignoring errors writing to host stdout/stderr. let _ignore = match link_name.as_str() { "miri_write_to_stdout" => std::io::stdout().write_all(msg), diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index d21a1560699..9ecbb18ef5a 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -157,6 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "ceilf32" | "truncf32" | "roundf32" + | "rintf32" => { let [f] = check_arg_count(args)?; // FIXME: Using host floats. @@ -174,6 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "ceilf32" => f.ceil(), "truncf32" => f.trunc(), "roundf32" => f.round(), + "rintf32" => f.round_ties_even(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; @@ -192,6 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "ceilf64" | "truncf64" | "roundf64" + | "rintf64" => { let [f] = check_arg_count(args)?; // FIXME: Using host floats. @@ -209,6 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "ceilf64" => f.ceil(), "truncf64" => f.trunc(), "roundf64" => f.round(), + "rintf64" => f.round_ties_even(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index d05c4d98fad..1eca389e984 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -17,7 +17,6 @@ use crate::shims::os_str::bytes_to_os_str; use crate::*; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; -use shims::unix::linux::fd::epoll::Epoll; #[derive(Debug)] pub struct FileHandle { @@ -25,17 +24,9 @@ pub struct FileHandle { writable: bool, } -pub trait FileDescriptor: std::fmt::Debug { +pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny { fn name(&self) -> &'static str; - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("{} cannot be used as FileHandle", self.name()); - } - - fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> { - throw_unsup_format!("not an epoll file descriptor"); - } - fn read<'tcx>( &mut self, _communicate_allowed: bool, @@ -69,7 +60,9 @@ pub trait FileDescriptor: std::fmt::Debug { fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>; - fn is_tty(&self) -> bool; + fn is_tty(&self) -> bool { + false + } #[cfg(unix)] fn as_unix_host_fd(&self) -> Option<i32> { @@ -82,10 +75,6 @@ impl FileDescriptor for FileHandle { "FILE" } - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - Ok(self) - } - fn read<'tcx>( &mut self, communicate_allowed: bool, @@ -271,10 +260,6 @@ impl FileDescriptor for NullOutput { fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { Ok(Box::new(NullOutput)) } - - fn is_tty(&self) -> bool { - false - } } #[derive(Debug)] @@ -694,7 +679,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`F_FULLFSYNC` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1530,7 +1520,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_i32( if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`ftruncate64` is only supported on file-backed file descriptors" + ) + })?; if *writable { if let Ok(length) = length.try_into() { let result = file.set_len(length); @@ -1571,7 +1566,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!("`fsync` is only supported on file-backed file descriptors") + })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { @@ -1593,7 +1591,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`fdatasync` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { @@ -1638,7 +1641,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let FileHandle { file, writable } = + file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`sync_data_range` is only supported on file-backed file descriptors" + ) + })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } else { @@ -1942,7 +1950,16 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option<FileMetadata>> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => &file_descriptor.as_file_handle()?.file, + Some(file_descriptor) => + &file_descriptor + .as_any() + .downcast_ref::<FileHandle>() + .ok_or_else(|| { + err_unsup_format!( + "obtaining metadata is only supported on file-backed file descriptors" + ) + })? + .file, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs index fd4927fa10c..3c4a678e598 100644 --- a/src/tools/miri/src/shims/unix/linux/fd.rs +++ b/src/tools/miri/src/shims/unix/linux/fd.rs @@ -80,7 +80,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let event = EpollEvent { events, data }; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.insert(fd, event); Ok(Scalar::from_i32(0)) @@ -89,7 +92,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } else if op == epoll_ctl_del { if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let epfd = epfd.as_epoll_handle()?; + let epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; epfd.file_descriptors.remove(&fd); Ok(Scalar::from_i32(0)) @@ -148,7 +154,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let numevents = 0; if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { - let _epfd = epfd.as_epoll_handle()?; + let _epfd = epfd + .as_any_mut() + .downcast_mut::<Epoll>() + .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; // FIXME return number of events ready when scheme for marking events ready exists Ok(Scalar::from_i32(numevents)) diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs index e33673fecf6..a429caaf8f4 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs @@ -32,18 +32,10 @@ impl FileDescriptor for Epoll { "epoll" } - fn as_epoll_handle<'tcx>(&mut self) -> InterpResult<'tcx, &mut Epoll> { - Ok(self) - } - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { Ok(Box::new(self.clone())) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs index b28a6e0c56e..1db020bb7b6 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/event.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs @@ -28,10 +28,6 @@ impl FileDescriptor for Event { Ok(Box::new(Event { val: self.val.clone() })) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs index f9e56b4a2b4..6adae88235f 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs @@ -19,10 +19,6 @@ impl FileDescriptor for SocketPair { Ok(Box::new(SocketPair)) } - fn is_tty(&self) -> bool { - false - } - fn close<'tcx>( self: Box<Self>, _communicate_allowed: bool, diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 1d7ed34c59a..21eaeabe6ad 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -139,8 +139,9 @@ regexes! { STDOUT: // Windows file paths r"\\" => "/", - // erase Stacked Borrows tags + // erase borrow tags "<[0-9]+>" => "<TAG>", + "<[0-9]+=" => "<TAG=", } regexes! { @@ -149,8 +150,9 @@ regexes! { r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", // erase alloc ids "alloc[0-9]+" => "ALLOC", - // erase Stacked Borrows tags + // erase borrow tags "<[0-9]+>" => "<TAG>", + "<[0-9]+=" => "<TAG=", // erase whitespace that differs between platforms r" +at (.*\.rs)" => " at $1", // erase generics in backtraces diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index a63cd03366f..0637e08af9b 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -1,4 +1,4 @@ -//! Make sure that a retag acts like a write for the data race model. +//! Make sure that a retag acts like a read for the data race model. //@compile-flags: -Zmiri-preemption-rate=0 #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs new file mode 100644 index 00000000000..122a8ff8752 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.rs @@ -0,0 +1,19 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Check that TB properly rejects alternating Reads and Writes, but tolerates +// alternating only Reads to Reserved mutable references. +pub fn main() { + let x = &mut 0u8; + let y = unsafe { &mut *(x as *mut u8) }; + // Foreign Read, but this is a no-op from the point of view of y (still Reserved) + let _val = *x; + // Now we activate y, for this to succeed y needs to not have been Frozen + // by the previous operation + *y += 1; // Success + // This time y gets Frozen... + let _val = *x; + // ... and the next Write attempt fails. + *y += 1; // Failure //~ ERROR: /write access through .* is forbidden/ + let _val = *x; + *y += 1; // Unreachable +} diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr new file mode 100644 index 00000000000..7c5bcd4e7b0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/alternate-read-write.rs:LL:CC + | +LL | *y += 1; // Failure + | ^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/alternate-read-write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs new file mode 100644 index 00000000000..215100de0a1 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.rs @@ -0,0 +1,42 @@ +//! Race-condition-like interaction between a read and a reborrow. +//! Even though no write or fake write occurs, reads have an effect on protected +//! Reserved. This is a protected-retag/read data race, but is not *detected* as +//! a data race violation because reborrows are not writes. +//! +//! This test is sensitive to the exact schedule so we disable preemption. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +use std::ptr::addr_of_mut; +use std::thread; + +#[derive(Copy, Clone)] +struct SendPtr(*mut u8); + +unsafe impl Send for SendPtr {} + +// First thread is just a reborrow, but for an instant `x` is +// protected and thus vulnerable to foreign reads. +fn thread_1(x: &mut u8) -> SendPtr { + thread::yield_now(); // make the other thread go first + SendPtr(x as *mut u8) +} + +// Second thread simply performs a read. +fn thread_2(x: &u8) { + let _val = *x; +} + +fn main() { + let mut x = 0u8; + let x_1 = unsafe { &mut *addr_of_mut!(x) }; + let xg = unsafe { &*addr_of_mut!(x) }; + + // The two threads are executed in parallel on aliasing pointers. + // UB occurs if the read of thread_2 occurs while the protector of thread_1 + // is in place. + let hf = thread::spawn(move || thread_1(x_1)); + let hg = thread::spawn(move || thread_2(xg)); + let SendPtr(p) = hf.join().unwrap(); + let () = hg.join().unwrap(); + + unsafe { *p = 1 }; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr new file mode 100644 index 00000000000..a078d18d3b0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/fragile-data-race.rs:LL:CC + | +LL | unsafe { *p = 1 }; + | ^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/fragile-data-race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.rs b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs new file mode 100644 index 00000000000..8450e1c168d --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Check that in the case of locations outside the range of a pointer, +// protectors trigger if and only if the location has already been accessed +fn main() { + unsafe { + let data = &mut [0u8, 1, 2, 3]; + let raw = data.as_mut_ptr(); + stuff(&mut *raw, raw); + } +} + +unsafe fn stuff(x: &mut u8, y: *mut u8) { + let xraw = x as *mut u8; + // No issue here: location 1 is not accessed + *y.add(1) = 42; + // Still no issue: location 2 is not invalidated + let _val = *xraw.add(2); + // However protector triggers if location is both accessed and invalidated + let _val = *xraw.add(3); + *y.add(3) = 42; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr new file mode 100644 index 00000000000..4396c63679e --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/outside-range.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected + --> $DIR/outside-range.rs:LL:CC + | +LL | *y.add(3) = 42; + | ^^^^^^^^^^^^^^ write access through <TAG> is forbidden because it is a foreign tag for <TAG>, which would hence change from Reserved to Disabled, but <TAG> is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `stuff` at $DIR/outside-range.rs:LL:CC +note: inside `main` + --> $DIR/outside-range.rs:LL:CC + | +LL | stuff(&mut *raw, raw); + | ^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs new file mode 100644 index 00000000000..025b7ad22dc --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.rs @@ -0,0 +1,14 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Read to local variable kills reborrows *and* raw pointers derived from them. +// This test would succeed under Stacked Borrows. +fn main() { + unsafe { + let mut root = 6u8; + let mref = &mut root; + let ptr = mref as *mut u8; + *ptr = 0; // Write + assert_eq!(root, 0); // Parent Read + *ptr = 0; //~ ERROR: /write access through .* is forbidden/ + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr new file mode 100644 index 00000000000..7d9367c87d0 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + --> $DIR/read-to-local.rs:LL:CC + | +LL | *ptr = 0; + | ^^^^^^^^ write access through <TAG> is forbidden because it is a child of <TAG> which is Frozen. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main` at $DIR/read-to-local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs new file mode 100644 index 00000000000..872efe3ad59 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +// Check how a Reserved with interior mutability +// responds to a Foreign Write under a Protector +#[path = "../../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +use std::cell::UnsafeCell; + +fn main() { + unsafe { + let n = &mut UnsafeCell::new(0u8); + name!(n.get(), "base"); + let x = &mut *(n as *mut UnsafeCell<_>); + name!(x.get(), "x"); + let y = (&mut *n).get(); + name!(y); + write_second(x, y); + unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) { + let alloc_id = alloc_id!(x.get()); + name!(x.get(), "callee:x"); + name!(x.get()=>1, "caller:x"); + name!(y, "callee:y"); + name!(y, "caller:y"); + print_state!(alloc_id); + // Right before the faulty Write, x is + // - Reserved + // - with interior mut + // - Protected + *y = 1; //~ ERROR: /write access through .* is forbidden/ + } + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr new file mode 100644 index 00000000000..8ae1c09470a --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/cell-protected-write.stderr @@ -0,0 +1,28 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └─┬──<TAG=base> +| Re*| ├─┬──<TAG=x> +| Re*| │ └─┬──<TAG=caller:x> +| Re*| │ └────<TAG=callee:x> Strongly protected +| Re*| └────<TAG=y,callee:y,caller:y> +────────────────────────────────────────────────────────────────────── +error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + --> $DIR/cell-protected-write.rs:LL:CC + | +LL | *y = 1; + | ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main::write_second` at $DIR/cell-protected-write.rs:LL:CC +note: inside `main` + --> $DIR/cell-protected-write.rs:LL:CC + | +LL | write_second(x, y); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs new file mode 100644 index 00000000000..3a1205a84f7 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// Check how a Reserved without interior mutability responds to a Foreign +// Write when under a protector +fn main() { + unsafe { + let n = &mut 0u8; + name!(n); + let x = &mut *(n as *mut _); + name!(x); + let y = (&mut *n) as *mut _; + name!(y); + write_second(x, y); + unsafe fn write_second(x: &mut u8, y: *mut u8) { + let alloc_id = alloc_id!(x); + name!(x, "callee:x"); + name!(x=>1, "caller:x"); + name!(y, "callee:y"); + name!(y, "caller:y"); + print_state!(alloc_id); + // Right before the faulty Write, x is + // - Reserved + // - Protected + // The Write turns it Disabled + *y = 0; //~ ERROR: /write access through .* is forbidden/ + } + } +} diff --git a/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr new file mode 100644 index 00000000000..a199fc0f0da --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/reserved/int-protected-write.stderr @@ -0,0 +1,28 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=n> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Res| │ └────<TAG=callee:x> Strongly protected +| Res| └────<TAG=y,callee:y,caller:y> +────────────────────────────────────────────────────────────────────── +error: Undefined Behavior: write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + --> $DIR/int-protected-write.rs:LL:CC + | +LL | *y = 0; + | ^^^^^^ write access through <TAG> (also named 'y,callee:y,caller:y') is forbidden because it is a foreign tag for <TAG> (also named 'callee:x'), which would hence change from Reserved to Disabled, but <TAG> (also named 'callee:x') is protected + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `main::write_second` at $DIR/int-protected-write.rs:LL:CC +note: inside `main` + --> $DIR/int-protected-write.rs:LL:CC + | +LL | write_second(x, y); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs new file mode 100644 index 00000000000..8ef3d23e804 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.rs @@ -0,0 +1,28 @@ +//! Make sure that a retag acts like a read for the data race model. +//! This is a retag/write race condition. +//! +//! This test is sensitive to the exact schedule so we disable preemption. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +#[derive(Copy, Clone)] +struct SendPtr(*mut u8); + +unsafe impl Send for SendPtr {} + +unsafe fn thread_1(SendPtr(p): SendPtr) { + let _r = &*p; +} + +unsafe fn thread_2(SendPtr(p): SendPtr) { + *p = 5; //~ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` +} + +fn main() { + let mut x = 0; + let p = std::ptr::addr_of_mut!(x); + let p = SendPtr(p); + + let t1 = std::thread::spawn(move || unsafe { thread_1(p) }); + let t2 = std::thread::spawn(move || unsafe { thread_2(p) }); + let _ = t1.join(); + let _ = t2.join(); +} diff --git a/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr new file mode 100644 index 00000000000..f2cdfe7c314 --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/retag-data-race.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/retag-data-race.rs:LL:CC + | +LL | *p = 5; + | ^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Write on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/retag-data-race.rs:LL:CC + | +LL | let _r = &*p; + | ^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside `thread_2` at $DIR/retag-data-race.rs:LL:CC +note: inside closure + --> $DIR/retag-data-race.rs:LL:CC + | +LL | let t2 = std::thread::spawn(move || unsafe { thread_2(p) }); + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs new file mode 100644 index 00000000000..6695d36306b --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows + +// We invalidate a reference during a 2-phase borrow by doing a Foreign +// Write in between the initial reborrow and function entry. UB occurs +// on function entry when reborrow from a Disabled fails. +// This test would pass under Stacked Borrows, but Tree Borrows +// is more strict on 2-phase borrows. + +struct Foo(u64); +impl Foo { + #[rustfmt::skip] // rustfmt is wrong about which line contains an error + fn add(&mut self, n: u64) -> u64 { //~ ERROR: /read access through .* is forbidden/ + self.0 + n + } +} + +pub fn main() { + let mut f = Foo(0); + let inner = &mut f.0 as *mut u64; + let _res = f.add(unsafe { + let n = f.0; + // This is the access at fault, but it's not immediately apparent because + // the reference that got invalidated is not under a Protector. + *inner = 42; + n + }); +} diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr new file mode 100644 index 00000000000..e511eb9cf8f --- /dev/null +++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled. + --> $DIR/write-during-2phase.rs:LL:CC + | +LL | fn add(&mut self, n: u64) -> u64 { + | ^^^^^^^^^ read access through <TAG> is forbidden because it is a child of <TAG> which is Disabled. + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = note: BACKTRACE: + = note: inside `Foo::add` at $DIR/write-during-2phase.rs:LL:CC +note: inside `main` + --> $DIR/write-during-2phase.rs:LL:CC + | +LL | let _res = f.add(unsafe { + | ________________^ +LL | | let n = f.0; +LL | | // This is the access at fault, but it's not immediately apparent because +LL | | // the reference that got invalidated is not under a Protector. +LL | | *inner = 42; +LL | | n +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs index 0051c62121c..cbf41d68b57 100644 --- a/src/tools/miri/tests/pass/adjacent-allocs.rs +++ b/src/tools/miri/tests/pass/adjacent-allocs.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance fn ensure_allocs_can_be_adjacent() { diff --git a/src/tools/miri/tests/pass/associated-const.rs b/src/tools/miri/tests/pass/associated-const.rs index 2ff08ffc4bf..331fbfcefde 100644 --- a/src/tools/miri/tests/pass/associated-const.rs +++ b/src/tools/miri/tests/pass/associated-const.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows trait Foo { const ID: i32; } diff --git a/src/tools/miri/tests/pass/assume_bug.rs b/src/tools/miri/tests/pass/assume_bug.rs index e14f875c022..662b9015088 100644 --- a/src/tools/miri/tests/pass/assume_bug.rs +++ b/src/tools/miri/tests/pass/assume_bug.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { vec![()].into_iter(); } diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index e3d80a78916..60b8ff87b59 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(strict_provenance, strict_provenance_atomic_ptr)] use std::sync::atomic::{ diff --git a/src/tools/miri/tests/pass/available-parallelism.rs b/src/tools/miri/tests/pass/available-parallelism.rs index eb4d09b1f54..77fb78424ba 100644 --- a/src/tools/miri/tests/pass/available-parallelism.rs +++ b/src/tools/miri/tests/pass/available-parallelism.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows fn main() { assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs index ef432a86d46..155e3d74ab9 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![allow(incomplete_features)] // for trait upcasting #![feature(allocator_api, trait_upcasting)] diff --git a/src/tools/miri/tests/pass/box.rs b/src/tools/miri/tests/pass/box.rs index 7bbe7be516b..3bb481aab88 100644 --- a/src/tools/miri/tests/pass/box.rs +++ b/src/tools/miri/tests/pass/box.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance #![feature(ptr_internals)] fn main() { diff --git a/src/tools/miri/tests/pass/box.stderr b/src/tools/miri/tests/pass/box.stack.stderr index 4c2fb40e110..4c2fb40e110 100644 --- a/src/tools/miri/tests/pass/box.stderr +++ b/src/tools/miri/tests/pass/box.stack.stderr diff --git a/src/tools/miri/tests/pass/box.stdout b/src/tools/miri/tests/pass/box.stack.stdout index 230ef368da6..230ef368da6 100644 --- a/src/tools/miri/tests/pass/box.stdout +++ b/src/tools/miri/tests/pass/box.stack.stdout diff --git a/src/tools/miri/tests/pass/box.tree.stdout b/src/tools/miri/tests/pass/box.tree.stdout new file mode 100644 index 00000000000..230ef368da6 --- /dev/null +++ b/src/tools/miri/tests/pass/box.tree.stdout @@ -0,0 +1,3 @@ +pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) } +foo #0 = Foo(42) +foo #1 = Foo(1337) diff --git a/src/tools/miri/tests/pass/btreemap.rs b/src/tools/miri/tests/pass/btreemap.rs index 040c648d474..b7c0406becc 100644 --- a/src/tools/miri/tests/pass/btreemap.rs +++ b/src/tools/miri/tests/pass/btreemap.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; diff --git a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs index d76c23633da..ccf96b99672 100644 --- a/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/src/tools/miri/tests/pass/concurrency/channels.rs b/src/tools/miri/tests/pass/concurrency/channels.rs index 53b57942d76..43086756b03 100644 --- a/src/tools/miri/tests/pass/concurrency/channels.rs +++ b/src/tools/miri/tests/pass/concurrency/channels.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 19ea6c130bd..3bd1e542407 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.stdout b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout index f2c036a1735..f2c036a1735 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.stdout +++ b/src/tools/miri/tests/pass/concurrency/sync.stack.stdout diff --git a/src/tools/miri/tests/pass/concurrency/sync.tree.stdout b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout new file mode 100644 index 00000000000..f2c036a1735 --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/sync.tree.stdout @@ -0,0 +1,20 @@ +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait diff --git a/src/tools/miri/tests/pass/concurrency/thread_locals.rs b/src/tools/miri/tests/pass/concurrency/thread_locals.rs index b19e56312f3..13c11b55775 100644 --- a/src/tools/miri/tests/pass/concurrency/thread_locals.rs +++ b/src/tools/miri/tests/pass/concurrency/thread_locals.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs index 7ccafec6037..bd06eec9cd5 100644 --- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.rs @@ -1,3 +1,6 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + use std::cell::RefCell; use std::thread; diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout index b7877820a0c..b7877820a0c 100644 --- a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stdout +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.stack.stdout diff --git a/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout new file mode 100644 index 00000000000..b7877820a0c --- /dev/null +++ b/src/tools/miri/tests/pass/concurrency/tls_lib_drop.tree.stdout @@ -0,0 +1,5 @@ +Dropping: 8 (should be before 'Continue main 1'). +Dropping: 8 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). +Continue main 2. diff --git a/src/tools/miri/tests/pass/disable-alignment-check.rs b/src/tools/miri/tests/pass/disable-alignment-check.rs index 366aff4a9f8..fdcacc6cea4 100644 --- a/src/tools/miri/tests/pass/disable-alignment-check.rs +++ b/src/tools/miri/tests/pass/disable-alignment-check.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-disable-alignment-check fn main() { diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs index 256c72add92..94cf465e884 100644 --- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs +++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/pass/extern_types.rs b/src/tools/miri/tests/pass/extern_types.rs index aa4c65ea892..7ac93577f0c 100644 --- a/src/tools/miri/tests/pass/extern_types.rs +++ b/src/tools/miri/tests/pass/extern_types.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance #![feature(extern_types)] extern "C" { diff --git a/src/tools/miri/tests/pass/extern_types.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 2e18f693058..2e18f693058 100644 --- a/src/tools/miri/tests/pass/extern_types.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index ce62fb0de04..fee5ca44ffb 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,4 +1,5 @@ #![feature(stmt_expr_attributes)] +#![feature(round_ties_even)] #![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; @@ -9,6 +10,7 @@ fn main() { more_casts(); ops(); nan_casts(); + rounding(); } // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. @@ -553,3 +555,31 @@ fn nan_casts() { assert!(nan1_32.is_nan()); assert!(nan2_32.is_nan()); } + +fn rounding() { + // Test cases taken from the library's tests for this feature + // f32 + assert_eq(2.5f32.round_ties_even(), 2.0f32); + assert_eq(1.0f32.round_ties_even(), 1.0f32); + assert_eq(1.3f32.round_ties_even(), 1.0f32); + assert_eq(1.5f32.round_ties_even(), 2.0f32); + assert_eq(1.7f32.round_ties_even(), 2.0f32); + assert_eq(0.0f32.round_ties_even(), 0.0f32); + assert_eq((-0.0f32).round_ties_even(), -0.0f32); + assert_eq((-1.0f32).round_ties_even(), -1.0f32); + assert_eq((-1.3f32).round_ties_even(), -1.0f32); + assert_eq((-1.5f32).round_ties_even(), -2.0f32); + assert_eq((-1.7f32).round_ties_even(), -2.0f32); + // f64 + assert_eq(2.5f64.round_ties_even(), 2.0f64); + assert_eq(1.0f64.round_ties_even(), 1.0f64); + assert_eq(1.3f64.round_ties_even(), 1.0f64); + assert_eq(1.5f64.round_ties_even(), 2.0f64); + assert_eq(1.7f64.round_ties_even(), 2.0f64); + assert_eq(0.0f64.round_ties_even(), 0.0f64); + assert_eq((-0.0f64).round_ties_even(), -0.0f64); + assert_eq((-1.0f64).round_ties_even(), -1.0f64); + assert_eq((-1.3f64).round_ties_even(), -1.0f64); + assert_eq((-1.5f64).round_ties_even(), -2.0f64); + assert_eq((-1.7f64).round_ties_even(), -2.0f64); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/future-self-referential.rs index 6994def16a1..763eceeb6f0 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs +++ b/src/tools/miri/tests/pass/future-self-referential.rs @@ -1,3 +1,6 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + use std::future::*; use std::marker::PhantomPinned; use std::pin::*; diff --git a/src/tools/miri/tests/pass/generator.rs b/src/tools/miri/tests/pass/generator.rs index 06f48666c55..e059c7114e3 100644 --- a/src/tools/miri/tests/pass/generator.rs +++ b/src/tools/miri/tests/pass/generator.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(generators, generator_trait, never_type)] use std::fmt::Debug; diff --git a/src/tools/miri/tests/pass/hashmap.rs b/src/tools/miri/tests/pass/hashmap.rs index 29ddd6c59a1..7224e357c6f 100644 --- a/src/tools/miri/tests/pass/hashmap.rs +++ b/src/tools/miri/tests/pass/hashmap.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows use std::collections::HashMap; use std::hash::BuildHasher; diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs index e7ff90cb6bf..42b6f433420 100644 --- a/src/tools/miri/tests/pass/intptrcast.rs +++ b/src/tools/miri/tests/pass/intptrcast.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance use std::mem; diff --git a/src/tools/miri/tests/pass/linked-list.rs b/src/tools/miri/tests/pass/linked-list.rs index 7377f9f60b0..36df30070cb 100644 --- a/src/tools/miri/tests/pass/linked-list.rs +++ b/src/tools/miri/tests/pass/linked-list.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(linked_list_cursors)] use std::collections::LinkedList; diff --git a/src/tools/miri/tests/pass/many_shr_bor.rs b/src/tools/miri/tests/pass/many_shr_bor.rs index 376b41dd6e2..aa960aa147a 100644 --- a/src/tools/miri/tests/pass/many_shr_bor.rs +++ b/src/tools/miri/tests/pass/many_shr_bor.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Make sure validation can handle many overlapping shared borrows for different parts of a data structure use std::cell::RefCell; diff --git a/src/tools/miri/tests/pass/memleak_ignored.rs b/src/tools/miri/tests/pass/memleak_ignored.rs index 60e06094e17..bba3207ee4c 100644 --- a/src/tools/miri/tests/pass/memleak_ignored.rs +++ b/src/tools/miri/tests/pass/memleak_ignored.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-ignore-leaks fn main() { diff --git a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs index 0786db1ef89..0ba6607a5d4 100644 --- a/src/tools/miri/tests/pass/option_box_transmute_ptr.rs +++ b/src/tools/miri/tests/pass/option_box_transmute_ptr.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // This tests that the size of Option<Box<i32>> is the same as *const i32. fn option_box_deref() -> i32 { let val = Some(Box::new(42)); diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs index d1340a04e04..1525ded6151 100644 --- a/src/tools/miri/tests/pass/pointers.rs +++ b/src/tools/miri/tests/pass/pointers.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance #![feature(ptr_metadata, const_raw_ptr_comparison)] diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs index c411f748a06..835daa36cfc 100644 --- a/src/tools/miri/tests/pass/provenance.rs +++ b/src/tools/miri/tests/pass/provenance.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(strict_provenance)] #![feature(pointer_byte_offsets)] use std::{mem, ptr}; diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs index 3044ac092b7..a2fcd098107 100644 --- a/src/tools/miri/tests/pass/ptr_int_casts.rs +++ b/src/tools/miri/tests/pass/ptr_int_casts.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs index ef7ff34d26b..35a52d0220b 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass/ptr_int_transmute.rs b/src/tools/miri/tests/pass/ptr_int_transmute.rs index ba50480c539..d99c25413e6 100644 --- a/src/tools/miri/tests/pass/ptr_int_transmute.rs +++ b/src/tools/miri/tests/pass/ptr_int_transmute.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows // Test what happens when we read parts of a pointer. // Related to <https://github.com/rust-lang/rust/issues/69488>. fn ptr_partial_read() { diff --git a/src/tools/miri/tests/pass/rc.rs b/src/tools/miri/tests/pass/rc.rs index 569dbc459a5..6375abcd232 100644 --- a/src/tools/miri/tests/pass/rc.rs +++ b/src/tools/miri/tests/pass/rc.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs index 642f75ecc09..458312508d2 100644 --- a/src/tools/miri/tests/pass/send-is-not-static-par-for.rs +++ b/src/tools/miri/tests/pass/send-is-not-static-par-for.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows use std::sync::Mutex; fn par_for<I, F>(iter: I, f: F) diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs index a56b97a5088..a99e921150b 100644 --- a/src/tools/miri/tests/pass/slices.rs +++ b/src/tools/miri/tests/pass/slices.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs index 3ca937ae13d..74761a89cb9 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs @@ -7,7 +7,7 @@ use std::{ extern "Rust" { fn miri_get_alloc_id(ptr: *const u8) -> u64; - fn miri_print_borrow_stacks(alloc_id: u64); + fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool); } fn get_alloc_id(ptr: *const u8) -> u64 { @@ -15,7 +15,9 @@ fn get_alloc_id(ptr: *const u8) -> u64 { } fn print_borrow_stacks(alloc_id: u64) { - unsafe { miri_print_borrow_stacks(alloc_id) } + unsafe { + miri_print_borrow_state(alloc_id, /* ignored: show_unnamed */ false) + } } fn main() { diff --git a/src/tools/miri/tests/pass/threadleak_ignored.rs b/src/tools/miri/tests/pass/threadleak_ignored.rs index a5f81573e96..d4899856194 100644 --- a/src/tools/miri/tests/pass/threadleak_ignored.rs +++ b/src/tools/miri/tests/pass/threadleak_ignored.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-ignore-leaks //! Test that leaking threads works, and that their destructors are not executed. diff --git a/src/tools/miri/tests/pass/threadleak_ignored.stderr b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr index 7557f49c758..7557f49c758 100644 --- a/src/tools/miri/tests/pass/threadleak_ignored.stderr +++ b/src/tools/miri/tests/pass/threadleak_ignored.stack.stderr diff --git a/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr new file mode 100644 index 00000000000..7557f49c758 --- /dev/null +++ b/src/tools/miri/tests/pass/threadleak_ignored.tree.stderr @@ -0,0 +1 @@ +Dropping 0 diff --git a/src/tools/miri/tests/pass/transmute_ptr.rs b/src/tools/miri/tests/pass/transmute_ptr.rs index fd9d457e440..ce6d86b7068 100644 --- a/src/tools/miri/tests/pass/transmute_ptr.rs +++ b/src/tools/miri/tests/pass/transmute_ptr.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(strict_provenance)] use std::{mem, ptr}; diff --git a/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs new file mode 100644 index 00000000000..af52f53791a --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/2phase-interiormut.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs, +// this is the opposite situation: the Write is not problematic because +// the Protector has not yet been added and the Reserved has interior +// mutability. +use core::cell::Cell; + +trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} +} +impl<T> Thing for Cell<T> {} + +fn main() { + let mut x = Cell::new(1); + let l = &x; + + x.do_the_thing({ + // Several Foreign accesses (both Reads and Writes) to the location + // being reborrowed. Reserved + unprotected + interior mut + // makes the pointer immune to everything as long as all accesses + // are child accesses to its parent pointer x. + x.set(3); + l.set(4); + x.get() + l.get() + }); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs new file mode 100644 index 00000000000..1bd94c6df67 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +use std::cell::UnsafeCell; + +// UnsafeCells use the parent tag, so it is possible to use them with +// few restrictions when only among themselves. +fn main() { + unsafe { + let data = &mut UnsafeCell::new(0u8); + name!(data.get(), "data"); + let x = &*data; + name!(x.get(), "x"); + let y = &*data; + name!(y.get(), "y"); + let alloc_id = alloc_id!(data.get()); + print_state!(alloc_id); + // y and x tolerate alternating Writes + *y.get() = 1; + *x.get() = 2; + *y.get() = 3; + *x.get() = 4; + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr new file mode 100644 index 00000000000..d4bc822b4bb --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/cell-alternate-writes.stderr @@ -0,0 +1,10 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └────<TAG=data,x,y> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └────<TAG=data,x,y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs new file mode 100644 index 00000000000..23250d6e6df --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/copy-nonoverlapping.rs @@ -0,0 +1,29 @@ +//@compile-flags: -Zmiri-tree-borrows + +// copy_nonoverlapping works regardless of the order in which we construct +// the arguments. +pub fn main() { + test_to_from(); + test_from_to(); +} + +fn test_to_from() { + unsafe { + let data = &mut [0u64, 1]; + let to = data.as_mut_ptr().add(1); + let from = data.as_ptr(); + std::ptr::copy_nonoverlapping(from, to, 1); + } +} + +// Stacked Borrows would not have liked this one because the `as_mut_ptr` reborrow +// invalidates the earlier pointer obtained from `as_ptr`, but Tree Borrows is fine +// with it. +fn test_from_to() { + unsafe { + let data = &mut [0u64, 1]; + let from = data.as_ptr(); + let to = data.as_mut_ptr().add(1); + std::ptr::copy_nonoverlapping(from, to, 1); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs new file mode 100644 index 00000000000..76bbc73e662 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.rs @@ -0,0 +1,32 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +// Check that a protector goes back to normal behavior when the function +// returns. +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +fn main() { + unsafe { + let data = &mut 0u8; + name!(data); + let alloc_id = alloc_id!(data); + let x = &mut *data; + name!(x); + print_state!(alloc_id); + do_nothing(x); // creates then removes a Protector for a child of x + let y = &mut *data; + name!(y); + print_state!(alloc_id); + // Invalidates the previous reborrow, but its Protector has been removed. + *y = 1; + print_state!(alloc_id); + } +} + +unsafe fn do_nothing(x: &mut u8) { + name!(x, "callee:x"); + name!(x=>1, "caller:x"); + let alloc_id = alloc_id!(x); + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr new file mode 100644 index 00000000000..d08d6948320 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/end-of-protector.stderr @@ -0,0 +1,32 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| └────<TAG=x> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| └─┬──<TAG=x> +| Res| └─┬──<TAG=caller:x> +| Res| └────<TAG=callee:x> Strongly protected +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=data> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Res| │ └────<TAG=callee:x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=data> +| Dis| ├─┬──<TAG=x> +| Dis| │ └─┬──<TAG=caller:x> +| Dis| │ └────<TAG=callee:x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.rs b/src/tools/miri/tests/pass/tree-borrows/formatting.rs new file mode 100644 index 00000000000..9021c417638 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/formatting.rs @@ -0,0 +1,73 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// Check the formatting of the trees. +fn main() { + unsafe { + alignment_check(); + structure_check(); + } +} + +// Alignment check: we split the array at indexes with different amounts of +// decimal digits to verify proper padding. +unsafe fn alignment_check() { + let data: &mut [u8] = &mut [0; 1024]; + name!(data.as_ptr()=>2, "data"); + let alloc_id = alloc_id!(data.as_ptr()); + let x = &mut data[1]; + name!(x as *mut _, "data[1]"); + *x = 1; + let x = &mut data[10]; + name!(x as *mut _, "data[10]"); + *x = 1; + let x = &mut data[100]; + name!(x as *mut _, "data[100]"); + *x = 1; + let _val = data[100]; // So that the above is Frz + let x = &mut data[1000]; + name!(x as *mut _, "data[1000]"); + *x = 1; + print_state!(alloc_id); +} + +// Tree structure check: somewhat complex organization of reborrows. +unsafe fn structure_check() { + let x = &0u8; + name!(x); + let xa = &*x; + name!(xa); + let xb = &*x; + name!(xb); + let xc = &*x; + name!(xc); + let xaa = &*xa; + name!(xaa); + let xab = &*xa; + name!(xab); + let xba = &*xb; + name!(xba); + let xbaa = &*xba; + name!(xbaa); + let xbaaa = &*xbaa; + name!(xbaaa); + let xbaaaa = &*xbaaa; + name!(xbaaaa); + let xca = &*xc; + name!(xca); + let xcb = &*xc; + name!(xcb); + let xcaa = &*xca; + name!(xcaa); + let xcab = &*xca; + name!(xcab); + let xcba = &*xcb; + name!(xcba); + let xcbb = &*xcb; + name!(xcbb); + let alloc_id = alloc_id!(x); + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/formatting.stderr b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr new file mode 100644 index 00000000000..a59775cf21f --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/formatting.stderr @@ -0,0 +1,29 @@ +───────────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1.. 2.. 10.. 11..100..101..1000..1001..1024 +| Res| Act| Res| Act| Res| Act| Res| Act| Res| └─┬──<TAG=data> +|----| Act|----|?Dis|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[1]> +|----|----|----| Act|----|?Dis| ----| ?Dis| ----| ├────<TAG=data[10]> +|----|----|----|----|----| Frz| ----| ?Dis| ----| ├────<TAG=data[100]> +|----|----|----|----|----|----| ----| Act| ----| └────<TAG=data[1000]> +───────────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Frz| └─┬──<TAG=x> +| Frz| ├─┬──<TAG=xa> +| Frz| │ ├────<TAG=xaa> +| Frz| │ └────<TAG=xab> +| Frz| ├─┬──<TAG=xb> +| Frz| │ └─┬──<TAG=xba> +| Frz| │ └─┬──<TAG=xbaa> +| Frz| │ └─┬──<TAG=xbaaa> +| Frz| │ └────<TAG=xbaaaa> +| Frz| └─┬──<TAG=xc> +| Frz| ├─┬──<TAG=xca> +| Frz| │ ├────<TAG=xcaa> +| Frz| │ └────<TAG=xcab> +| Frz| └─┬──<TAG=xcb> +| Frz| ├────<TAG=xcba> +| Frz| └────<TAG=xcbb> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs new file mode 100644 index 00000000000..4daf06c777e --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/read-only-from-mut.rs @@ -0,0 +1,14 @@ +//@compile-flags: -Zmiri-tree-borrows + +// Tree Borrows has no issue with several mutable references existing +// at the same time, as long as they are used only immutably. +// I.e. multiple Reserved can coexist. +pub fn main() { + unsafe { + let base = &mut 42u64; + let r1 = &mut *(base as *mut u64); + let r2 = &mut *(base as *mut u64); + let _l = *r1; + let _l = *r2; + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs new file mode 100644 index 00000000000..e3f3f2d4032 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.rs @@ -0,0 +1,24 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; + +// To check that a reborrow is counted as a Read access, we use a reborrow +// with no additional Read to Freeze an Active pointer. + +fn main() { + unsafe { + let parent = &mut 0u8; + name!(parent); + let alloc_id = alloc_id!(parent); + let x = &mut *parent; + name!(x); + *x = 0; // x is now Active + print_state!(alloc_id); + let y = &mut *parent; + name!(y); + // Check in the debug output that x has been Frozen by the reborrow + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr new file mode 100644 index 00000000000..b9c52c20640 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reborrow-is-read.stderr @@ -0,0 +1,13 @@ +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=parent> +| Act| └────<TAG=x> +────────────────────────────────────────────────────────────────────── +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=parent> +| Frz| ├────<TAG=x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.rs b/src/tools/miri/tests/pass/tree-borrows/reserved.rs new file mode 100644 index 00000000000..d8a8c27568d --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reserved.rs @@ -0,0 +1,127 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 + +#[path = "../../utils/mod.rs"] +mod utils; +use utils::macros::*; +use utils::miri_extern::miri_write_to_stderr; + +use std::cell::UnsafeCell; + +// We exhaustively check that Reserved behaves as we want under all of the +// following conditions: +// - with or without interior mutability +// - with or without a protector +// - for a foreign read or write +// Of these cases, those in this file are the ones that must not cause +// immediate UB, and those that do are in tests/fail/tree-borrows/reserved/ +// and are the combinations [_ + protected + write] + +fn main() { + unsafe { + cell_protected_read(); + cell_unprotected_read(); + cell_unprotected_write(); + int_protected_read(); + int_unprotected_read(); + int_unprotected_write(); + } +} + +unsafe fn print(msg: &str) { + miri_write_to_stderr(msg.as_bytes()); + miri_write_to_stderr("\n".as_bytes()); +} + +unsafe fn read_second<T>(x: &mut T, y: *mut u8) { + name!(x as *mut T as *mut u8=>1, "caller:x"); + name!(x as *mut T as *mut u8, "callee:x"); + name!(y, "caller:y"); + name!(y, "callee:y"); + let _val = *y; +} + +// Foreign Read on a interior mutable Protected Reserved turns it Frozen. +unsafe fn cell_protected_read() { + print("[interior mut + protected] Foreign Read: Re* -> Frz"); + let base = &mut UnsafeCell::new(0u8); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<u8>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + read_second(x, y); // Foreign Read for callee:x + print_state!(alloc_id); +} + +// Foreign Read on an interior mutable pointer is a noop. +unsafe fn cell_unprotected_read() { + print("[interior mut] Foreign Read: Re* -> Re*"); + let base = &mut UnsafeCell::new(0u64); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<_>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + let _val = *y; // Foreign Read for x + print_state!(alloc_id); +} + +// Foreign Write on an interior mutable pointer is a noop. +// Also y must become Active. +unsafe fn cell_unprotected_write() { + print("[interior mut] Foreign Write: Re* -> Re*"); + let base = &mut UnsafeCell::new(0u64); + name!(base.get(), "base"); + let alloc_id = alloc_id!(base.get()); + let x = &mut *(base as *mut UnsafeCell<u64>); + name!(x.get(), "x"); + let y = (&mut *base).get(); + name!(y); + *y = 1; // Foreign Write for x + print_state!(alloc_id); +} + +// Foreign Read on a Protected Reserved turns it Frozen. +unsafe fn int_protected_read() { + print("[protected] Foreign Read: Res -> Frz"); + let base = &mut 0u8; + let alloc_id = alloc_id!(base); + name!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + read_second(x, y); // Foreign Read for callee:x + print_state!(alloc_id); +} + +// Foreign Read on a Reserved is a noop. +// Also y must become Active. +unsafe fn int_unprotected_read() { + print("[] Foreign Read: Res -> Res"); + let base = &mut 0u8; + name!(base); + let alloc_id = alloc_id!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + let _val = *y; // Foreign Read for x + print_state!(alloc_id); +} + +// Foreign Write on a Reserved turns it Disabled. +unsafe fn int_unprotected_write() { + print("[] Foreign Write: Res -> Dis"); + let base = &mut 0u8; + name!(base); + let alloc_id = alloc_id!(base); + let x = &mut *(base as *mut u8); + name!(x); + let y = (&mut *base) as *mut u8; + name!(y); + *y = 1; // Foreign Write for x + print_state!(alloc_id); +} diff --git a/src/tools/miri/tests/pass/tree-borrows/reserved.stderr b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr new file mode 100644 index 00000000000..d76ee0f8266 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/reserved.stderr @@ -0,0 +1,52 @@ +[interior mut + protected] Foreign Read: Re* -> Frz +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Re*| └─┬──<TAG=base> +| Re*| ├─┬──<TAG=x> +| Re*| │ └─┬──<TAG=caller:x> +| Frz| │ └────<TAG=callee:x> +| Re*| └────<TAG=y,caller:y,callee:y> +────────────────────────────────────────────────────────────────────── +[interior mut] Foreign Read: Re* -> Re* +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 8 +| Re*| └─┬──<TAG=base> +| Re*| ├────<TAG=x> +| Re*| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[interior mut] Foreign Write: Re* -> Re* +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 8 +| Act| └─┬──<TAG=base> +| Re*| ├────<TAG=x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[protected] Foreign Read: Res -> Frz +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=base> +| Res| ├─┬──<TAG=x> +| Res| │ └─┬──<TAG=caller:x> +| Frz| │ └────<TAG=callee:x> +| Res| └────<TAG=y,caller:y,callee:y> +────────────────────────────────────────────────────────────────────── +[] Foreign Read: Res -> Res +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Res| └─┬──<TAG=base> +| Res| ├────<TAG=x> +| Res| └────<TAG=y> +────────────────────────────────────────────────────────────────────── +[] Foreign Write: Res -> Dis +────────────────────────────────────────────────────────────────────── +Warning: this tree is indicative only. Some tags may have been hidden. +0.. 1 +| Act| └─┬──<TAG=base> +| Dis| ├────<TAG=x> +| Act| └────<TAG=y> +────────────────────────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs new file mode 100644 index 00000000000..e1a9334ab54 --- /dev/null +++ b/src/tools/miri/tests/pass/tree-borrows/transmute-unsafecell.rs @@ -0,0 +1,13 @@ +//@compile-flags: -Zmiri-tree-borrows + +use core::cell::UnsafeCell; +use core::mem; + +fn main() { + unsafe { + let x = &0i32; + // As long as we only read, transmuting this to UnsafeCell should be fine. + let cell_x: &UnsafeCell<i32> = mem::transmute(&x); + let _val = *cell_x.get(); + } +} diff --git a/src/tools/miri/tests/pass/unsized.rs b/src/tools/miri/tests/pass/unsized.rs index d9beac4327d..c9046dc3c76 100644 --- a/src/tools/miri/tests/pass/unsized.rs +++ b/src/tools/miri/tests/pass/unsized.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(unsized_tuple_coercion)] #![feature(unsized_fn_params)] diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 30a28bc5803..06ec2f99172 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance #![feature(iter_advance_by, iter_next_chunk)] diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs index 6f56f9d103e..dfbf9bb83c1 100644 --- a/src/tools/miri/tests/pass/vecdeque.rs +++ b/src/tools/miri/tests/pass/vecdeque.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; diff --git a/src/tools/miri/tests/pass/vecdeque.stdout b/src/tools/miri/tests/pass/vecdeque.stack.stdout index 63de960ee2b..63de960ee2b 100644 --- a/src/tools/miri/tests/pass/vecdeque.stdout +++ b/src/tools/miri/tests/pass/vecdeque.stack.stdout diff --git a/src/tools/miri/tests/pass/vecdeque.tree.stdout b/src/tools/miri/tests/pass/vecdeque.tree.stdout new file mode 100644 index 00000000000..63de960ee2b --- /dev/null +++ b/src/tools/miri/tests/pass/vecdeque.tree.stdout @@ -0,0 +1,2 @@ +[2, 2] Iter([2, 2], []) +Iter([], []) diff --git a/src/tools/miri/tests/utils/macros.rs b/src/tools/miri/tests/utils/macros.rs new file mode 100644 index 00000000000..de223410fba --- /dev/null +++ b/src/tools/miri/tests/utils/macros.rs @@ -0,0 +1,61 @@ +#![allow(unused_macros)] +#![allow(unused_macro_rules)] +#![allow(unused_imports)] + +/// `alloc_id!(ptr)`: obtain the allocation id from a pointer. +/// +/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`. +/// +/// The id obtained can be passed directly to `print_state!`. +macro_rules! alloc_id { + ($ptr:expr) => { + crate::utils::miri_extern::miri_get_alloc_id($ptr as *const u8 as *const ()) + }; +} + +/// `print_state!(alloc_id, show_unnamed)`: print the internal state of the borrow +/// tracker (stack or tree). +/// +/// `alloc_id` should be obtained from `alloc_id!`. +/// +/// `show_unnamed` is an optional boolean that determines if Tree Borrows displays +/// tags that have not been given a name. Defaults to `false`. +macro_rules! print_state { + ($alloc_id:expr) => { + crate::utils::macros::print_state!($alloc_id, false); + }; + ($alloc_id:expr, $show:expr) => { + crate::utils::miri_extern::miri_print_borrow_state($alloc_id, $show); + }; +} + +/// `name!(ptr => nth_parent, name)`: associate `name` to the `nth_parent` of `ptr`. +/// +/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`. +/// +/// `nth_parent` is an optional `u8` that defaults to 0. The corresponding ancestor +/// of the tag of `ptr` will be searched: 0 for `ptr` itself, 1 for the direct parent +/// of `ptr`, 2 for the grandparent, etc. If `nth_parent` is not specified, +/// then `=>` should also not be included. +/// +/// `name` is an optional string that will be used as the name. Defaults to +/// `stringify!($ptr)` the name of `ptr` in the source code. +macro_rules! name { + ($ptr:expr, $name:expr) => { + crate::utils::macros::name!($ptr => 0, $name); + }; + ($ptr:expr) => { + crate::utils::macros::name!($ptr => 0, stringify!($ptr)); + }; + ($ptr:expr => $nb:expr) => { + crate::utils::macros::name!($ptr => $nb, stringify!($ptr)); + }; + ($ptr:expr => $nb:expr, $name:expr) => { + let name = $name.as_bytes(); + crate::utils::miri_extern::miri_pointer_name($ptr as *const u8 as *const (), $nb, name); + }; +} + +pub(crate) use alloc_id; +pub(crate) use name; +pub(crate) use print_state; diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs new file mode 100644 index 00000000000..6c4298c613b --- /dev/null +++ b/src/tools/miri/tests/utils/miri_extern.rs @@ -0,0 +1,142 @@ +#![allow(dead_code)] + +#[repr(C)] +/// Layout of the return value of `miri_resolve_frame`, +/// with fields in the exact same order. +pub struct MiriFrame { + // The size of the name of the function being executed, encoded in UTF-8 + pub name_len: usize, + // The size of filename of the function being executed, encoded in UTF-8 + pub filename_len: usize, + // The line number currently being executed in `filename`, starting from '1'. + pub lineno: u32, + // The column number currently being executed in `filename`, starting from '1'. + pub colno: u32, + // The function pointer to the function currently being executed. + // This can be compared against function pointers obtained by + // casting a function (e.g. `my_fn as *mut ()`) + pub fn_ptr: *mut (), +} + +#[cfg(miri)] +extern "Rust" { + /// Miri-provided extern function to mark the block `ptr` points to as a "root" + /// for some static memory. This memory and everything reachable by it is not + /// considered leaking even if it still exists when the program terminates. + /// + /// `ptr` has to point to the beginning of an allocated block. + pub fn miri_static_root(ptr: *const u8); + + // Miri-provided extern function to get the amount of frames in the current backtrace. + // The `flags` argument must be `0`. + pub fn miri_backtrace_size(flags: u64) -> usize; + + /// Miri-provided extern function to obtain a backtrace of the current call stack. + /// This writes a slice of pointers into `buf` - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame`. + /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. + /// The `flags` argument must be `1`. + pub fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + + /// Miri-provided extern function to resolve a frame pointer obtained + /// from `miri_get_backtrace`. The `flags` argument must be `1`. + /// + /// This function can be called on any thread (not just the one which obtained `frame`). + pub fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; + + /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. + /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. + /// The flags argument must be `0`. + pub fn miri_resolve_frame_names( + ptr: *mut (), + flags: u64, + name_buf: *mut u8, + filename_buf: *mut u8, + ); + + /// Miri-provided extern function to begin unwinding with the given payload. + /// + /// This is internal and unstable and should not be used; we give it here + /// just to be complete. + pub fn miri_start_panic(payload: *mut u8) -> !; + + /// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer + /// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort. + /// + /// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because + /// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation. + /// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so + /// inherits all of its instability. + pub fn miri_get_alloc_id(ptr: *const ()) -> u64; + + /// Miri-provided extern function to print (from the interpreter, not the program) the contents of all + /// borrows in an allocation. + /// + /// If Stacked Borrows is running, this prints all the stacks. The leftmost tag is the bottom of the stack. + /// + /// If Tree borrows is running, this prints on the left the permissions of each tag on each range, + /// an on the right the tree structure of the tags. If some tags were named via `miri_pointer_name`, + /// their names appear here. + /// + /// If additionally `show_unnamed` is `false` then tags that did *not* receive a name will be hidden. + /// Ensure that either the important tags have been named, or `show_unnamed = true`. + /// Note: as Stacked Borrows does not have tag names at all, `show_unnamed` is ignored and all tags are shown. + /// In general, unless you strongly want some tags to be hidden (as is the case in `tree-borrows` tests), + /// `show_unnamed = true` should be the default. + /// + /// The format of what this emits is unstable and may change at any time. In particular, users should be + /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of + /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. + /// + /// This function is extremely unstable. At any time the format of its output may change, its signature may + /// change, or it may be removed entirely. + pub fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool); + + /// Miri-provided extern function to associate a name to the nth parent of a tag. + /// Typically the name given would be the name of the program variable that holds the pointer. + /// Unreachable tags can still be named by using nonzero `nth_parent` and a child tag. + /// + /// This function does nothing under Stacked Borrows, since Stacked Borrows's implementation + /// of `miri_print_borrow_state` does not show the names. + /// + /// Under Tree Borrows, the names also appear in error messages. + pub fn miri_pointer_name(ptr: *const (), nth_parent: u8, name: &[u8]); + + /// Miri-provided extern function to print (from the interpreter, not the + /// program) the contents of a section of program memory, as bytes. Bytes + /// written using this function will emerge from the interpreter's stdout. + pub fn miri_write_to_stdout(bytes: &[u8]); + + /// Miri-provided extern function to print (from the interpreter, not the + /// program) the contents of a section of program memory, as bytes. Bytes + /// written using this function will emerge from the interpreter's stderr. + pub fn miri_write_to_stderr(bytes: &[u8]); + + /// Miri-provided extern function to allocate memory from the interpreter. + /// + /// This is useful when no fundamental way of allocating memory is + /// available, e.g. when using `no_std` + `alloc`. + pub fn miri_alloc(size: usize, align: usize) -> *mut u8; + + /// Miri-provided extern function to deallocate memory. + pub fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); + + /// Convert a path from the host Miri runs on to the target Miri interprets. + /// Performs conversion of path separators as needed. + /// + /// Usually Miri performs this kind of conversion automatically. However, manual conversion + /// might be necessary when reading an environment variable that was set on the host + /// (such as TMPDIR) and using it as a target path. + /// + /// Only works with isolation disabled. + /// + /// `in` must point to a null-terminated string, and will be read as the input host path. + /// `out` must point to at least `out_size` many bytes, and the result will be stored there + /// with a null terminator. + /// Returns 0 if the `out` buffer was large enough, and the required size otherwise. + pub fn miri_host_to_target_path( + path: *const std::ffi::c_char, + out: *mut std::ffi::c_char, + out_size: usize, + ) -> usize; +} diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs new file mode 100644 index 00000000000..e1ea77e4df8 --- /dev/null +++ b/src/tools/miri/tests/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod macros; +pub mod miri_extern; diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 2d6abe59343..070ce93f97c 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -103,7 +103,7 @@ mod os_impl { // FIXME: we don't need to look at all binaries, only files that have been modified in this branch // (e.g. using `git ls-files`). - walk_no_read(path, |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| { + walk_no_read(&[path], |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| { let file = entry.path(); let extension = file.extension(); let scripts = ["py", "sh", "ps1"]; diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs index 2241375eaae..84b13306805 100644 --- a/src/tools/tidy/src/debug_artifacts.rs +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -1,21 +1,15 @@ //! Tidy check to prevent creation of unnecessary debug artifacts while running tests. -use crate::walk::{filter_dirs, walk}; +use crate::walk::{filter_dirs, filter_not_rust, walk}; use std::path::Path; const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test"; pub fn check(test_dir: &Path, bad: &mut bool) { - walk(test_dir, filter_dirs, &mut |entry, contents| { - let filename = entry.path(); - let is_rust = filename.extension().map_or(false, |ext| ext == "rs"); - if !is_rust { - return; - } - + walk(test_dir, |path| filter_dirs(path) || filter_not_rust(path), &mut |entry, contents| { for (i, line) in contents.lines().enumerate() { if line.contains("borrowck_graphviz_postflow") { - tidy_error!(bad, "{}:{}: {}", filename.display(), i + 1, GRAPHVIZ_POSTFLOW_MSG); + tidy_error!(bad, "{}:{}: {}", entry.path().display(), i + 1, GRAPHVIZ_POSTFLOW_MSG); } } }); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 6d94417a10f..f18feda533c 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -9,8 +9,9 @@ //! * All unstable lang features have tests to ensure they are actually unstable. //! * Language features in a group are sorted by feature name. -use crate::walk::{filter_dirs, walk, walk_many}; +use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many}; use std::collections::hash_map::{Entry, HashMap}; +use std::ffi::OsStr; use std::fmt; use std::fs; use std::num::NonZeroU32; @@ -101,17 +102,15 @@ pub fn check( &tests_path.join("rustdoc-ui"), &tests_path.join("rustdoc"), ], - filter_dirs, + |path| { + filter_dirs(path) + || filter_not_rust(path) + || path.file_name() == Some(OsStr::new("features.rs")) + || path.file_name() == Some(OsStr::new("diagnostic_list.rs")) + }, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); - if !filename.ends_with(".rs") - || filename == "features.rs" - || filename == "diagnostic_list.rs" - { - return; - } - let filen_underscore = filename.replace('-', "_").replace(".rs", ""); let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features); diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d98758ace4f..f59406c404b 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -13,7 +13,7 @@ use std::path::PathBuf; use std::process; use std::str::FromStr; use std::sync::atomic::{AtomicBool, Ordering}; -use std::thread::{scope, ScopedJoinHandle}; +use std::thread::{self, scope, ScopedJoinHandle}; fn main() { let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); @@ -55,16 +55,28 @@ fn main() { VecDeque::with_capacity(concurrency.get()); macro_rules! check { - ($p:ident $(, $args:expr)* ) => { + ($p:ident) => { + check!(@ $p, name=format!("{}", stringify!($p))); + }; + ($p:ident, $path:expr $(, $args:expr)* ) => { + let shortened = $path.strip_prefix(&root_path).unwrap(); + let name = if shortened == std::path::Path::new("") { + format!("{} (.)", stringify!($p)) + } else { + format!("{} ({})", stringify!($p), shortened.display()) + }; + check!(@ $p, name=name, $path $(,$args)*); + }; + (@ $p:ident, name=$name:expr $(, $args:expr)* ) => { drain_handles(&mut handles); - let handle = s.spawn(|| { + let handle = thread::Builder::new().name($name).spawn_scoped(s, || { let mut flag = false; $p::check($($args, )* &mut flag); if (flag) { bad.store(true, Ordering::Relaxed); } - }); + }).unwrap(); handles.push_back(handle); } } @@ -108,7 +120,6 @@ fn main() { check!(edition, &library_path); check!(alphabetical, &src_path); - check!(alphabetical, &tests_path); check!(alphabetical, &compiler_path); check!(alphabetical, &library_path); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 868579b4b1a..6b7b27fd526 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -59,7 +59,6 @@ const EXCEPTION_PATHS: &[&str] = &[ "library/std/src/path.rs", "library/std/src/sys_common", // Should only contain abstractions over platforms "library/std/src/net/test.rs", // Utility helpers for tests - "library/std/src/panic.rs", // fuchsia-specific panic backtrace handling "library/std/src/personality.rs", "library/std/src/personality/", ]; diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 75a4586cb7f..a965c98f484 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -19,7 +19,7 @@ use crate::walk::{filter_dirs, walk}; use regex::{Regex, RegexSet}; -use std::path::Path; +use std::{ffi::OsStr, path::Path}; /// Error code markdown is restricted to 80 columns because they can be /// displayed on the console with --example. @@ -228,21 +228,33 @@ fn is_unexplained_ignore(extension: &str, line: &str) -> bool { pub fn check(path: &Path, bad: &mut bool) { fn skip(path: &Path) -> bool { - filter_dirs(path) || skip_markdown_path(path) + if path.file_name().map_or(false, |name| name.to_string_lossy().starts_with(".#")) { + // vim or emacs temporary file + return true; + } + + if filter_dirs(path) || skip_markdown_path(path) { + return true; + } + + let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"]; + if extensions.iter().all(|e| path.extension() != Some(OsStr::new(e))) { + return true; + } + + // We only check CSS files in rustdoc. + path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc") } + let problematic_consts_strings: Vec<String> = (PROBLEMATIC_CONSTS.iter().map(u32::to_string)) .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v))) .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v))) .collect(); let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); + walk(path, skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); - let extensions = - [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl", ".goml"]; - if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") { - return; - } let is_style_file = filename.ends_with(".css"); let under_rustfmt = filename.ends_with(".rs") && @@ -253,11 +265,6 @@ pub fn check(path: &Path, bad: &mut bool) { a.ends_with("src/doc/book") }); - if is_style_file && !is_in(file, "src", "librustdoc") { - // We only check CSS files in rustdoc. - return; - } - if contents.is_empty() { tidy_error!(bad, "{}: empty file", file.display()); } diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index f41fa4fcce1..e0fa6aceb85 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -4,6 +4,8 @@ use std::collections::BTreeMap; use std::path::Path; +use crate::walk::filter_not_rust; + const COMMENT: &str = "//"; const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:"; const COMPILE_FLAGS_HEADER: &str = "compile-flags:"; @@ -35,61 +37,57 @@ struct RevisionInfo<'a> { } pub fn check(path: &Path, bad: &mut bool) { - crate::walk::walk( - path, - |path| path.extension().map(|p| p == "rs") == Some(false), - &mut |entry, content| { - let file = entry.path().display(); - let mut header_map = BTreeMap::new(); - iter_header(content, &mut |cfg, directive| { - if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) { - let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); - let comp_vec = info.llvm_components.get_or_insert(Vec::new()); - for component in value.split(' ') { - let component = component.trim(); - if !component.is_empty() { - comp_vec.push(component); - } - } - } else if directive.starts_with(COMPILE_FLAGS_HEADER) { - let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..]; - if let Some((_, v)) = compile_flags.split_once("--target") { - if let Some((arch, _)) = - v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-") - { - let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); - info.target_arch.replace(arch); - } else { - eprintln!("{file}: seems to have a malformed --target value"); - *bad = true; - } + crate::walk::walk(path, filter_not_rust, &mut |entry, content| { + let file = entry.path().display(); + let mut header_map = BTreeMap::new(); + iter_header(content, &mut |cfg, directive| { + if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) { + let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); + let comp_vec = info.llvm_components.get_or_insert(Vec::new()); + for component in value.split(' ') { + let component = component.trim(); + if !component.is_empty() { + comp_vec.push(component); } } - }); - for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map { - let rev = rev.unwrap_or("[unspecified]"); - match (target_arch, llvm_components) { - (None, None) => {} - (Some(_), None) => { - eprintln!( - "{}: revision {} should specify `{}` as it has `--target` set", - file, rev, LLVM_COMPONENTS_HEADER - ); + } else if directive.starts_with(COMPILE_FLAGS_HEADER) { + let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..]; + if let Some((_, v)) = compile_flags.split_once("--target") { + if let Some((arch, _)) = + v.trim_start_matches(|c| c == ' ' || c == '=').split_once("-") + { + let info = header_map.entry(cfg).or_insert(RevisionInfo::default()); + info.target_arch.replace(arch); + } else { + eprintln!("{file}: seems to have a malformed --target value"); *bad = true; } - (None, Some(_)) => { - eprintln!( - "{}: revision {} should not specify `{}` as it doesn't need `--target`", - file, rev, LLVM_COMPONENTS_HEADER - ); - *bad = true; - } - (Some(_), Some(_)) => { - // FIXME: check specified components against the target architectures we - // gathered. - } } } - }, - ); + }); + for (rev, RevisionInfo { target_arch, llvm_components }) in &header_map { + let rev = rev.unwrap_or("[unspecified]"); + match (target_arch, llvm_components) { + (None, None) => {} + (Some(_), None) => { + eprintln!( + "{}: revision {} should specify `{}` as it has `--target` set", + file, rev, LLVM_COMPONENTS_HEADER + ); + *bad = true; + } + (None, Some(_)) => { + eprintln!( + "{}: revision {} should not specify `{}` as it doesn't need `--target`", + file, rev, LLVM_COMPONENTS_HEADER + ); + *bad = true; + } + (Some(_), Some(_)) => { + // FIXME: check specified components against the target architectures we + // gathered. + } + } + } + }); } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 15c36923e88..66f5c932be2 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -3,87 +3,83 @@ //! - there are no stray `.stderr` files use ignore::Walk; -use ignore::WalkBuilder; +use std::collections::HashMap; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. const ROOT_ENTRY_LIMIT: usize = 940; const ISSUES_ENTRY_LIMIT: usize = 1978; -fn check_entries(path: &Path, bad: &mut bool) { - for dir in Walk::new(&path.join("ui")) { +fn check_entries(tests_path: &Path, bad: &mut bool) { + let mut directories: HashMap<PathBuf, usize> = HashMap::new(); + + for dir in Walk::new(&tests_path.join("ui")) { if let Ok(entry) = dir { - if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) { - let dir_path = entry.path(); - // Use special values for these dirs. - let is_root = path.join("ui") == dir_path; - let is_issues_dir = path.join("ui/issues") == dir_path; - let limit = if is_root { - ROOT_ENTRY_LIMIT - } else if is_issues_dir { - ISSUES_ENTRY_LIMIT - } else { - ENTRY_LIMIT - }; + let parent = entry.path().parent().unwrap().to_path_buf(); + *directories.entry(parent).or_default() += 1; + } + } - let count = WalkBuilder::new(&dir_path) - .max_depth(Some(1)) - .build() - .into_iter() - .collect::<Vec<_>>() - .len() - - 1; // remove the dir itself + for (dir_path, count) in directories { + // Use special values for these dirs. + let is_root = tests_path.join("ui") == dir_path; + let is_issues_dir = tests_path.join("ui/issues") == dir_path; + let limit = if is_root { + ROOT_ENTRY_LIMIT + } else if is_issues_dir { + ISSUES_ENTRY_LIMIT + } else { + ENTRY_LIMIT + }; - if count > limit { - tidy_error!( - bad, - "following path contains more than {} entries, \ - you should move the test to some relevant subdirectory (current: {}): {}", - limit, - count, - dir_path.display() - ); - } - } + if count > limit { + tidy_error!( + bad, + "following path contains more than {} entries, \ + you should move the test to some relevant subdirectory (current: {}): {}", + limit, + count, + dir_path.display() + ); } } } pub fn check(path: &Path, bad: &mut bool) { check_entries(&path, bad); - for path in &[&path.join("ui"), &path.join("ui-fulldeps")] { - crate::walk::walk_no_read(path, |_| false, &mut |entry| { - let file_path = entry.path(); - if let Some(ext) = file_path.extension() { - if ext == "stderr" || ext == "stdout" { - // Test output filenames have one of the formats: - // ``` - // $testname.stderr - // $testname.$mode.stderr - // $testname.$revision.stderr - // $testname.$revision.$mode.stderr - // ``` - // - // For now, just make sure that there is a corresponding - // `$testname.rs` file. - // - // NB: We do not use file_stem() as some file names have multiple `.`s and we - // must strip all of them. - let testname = - file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; - if !file_path.with_file_name(testname).with_extension("rs").exists() { - tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); - } + let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps")); + let paths = [ui.as_path(), ui_fulldeps.as_path()]; + crate::walk::walk_no_read(&paths, |_| false, &mut |entry| { + let file_path = entry.path(); + if let Some(ext) = file_path.extension() { + if ext == "stderr" || ext == "stdout" { + // Test output filenames have one of the formats: + // ``` + // $testname.stderr + // $testname.$mode.stderr + // $testname.$revision.stderr + // $testname.$revision.$mode.stderr + // ``` + // + // For now, just make sure that there is a corresponding + // `$testname.rs` file. + // + // NB: We do not use file_stem() as some file names have multiple `.`s and we + // must strip all of them. + let testname = + file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; + if !file_path.with_file_name(testname).with_extension("rs").exists() { + tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); + } - if let Ok(metadata) = fs::metadata(file_path) { - if metadata.len() == 0 { - tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); - } + if let Ok(metadata) = fs::metadata(file_path) { + if metadata.len() == 0 { + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } } - }); - } + } + }); } diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 94152e75168..2ade22c209f 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -1,6 +1,6 @@ use ignore::DirEntry; -use std::{fs::File, io::Read, path::Path}; +use std::{ffi::OsStr, fs::File, io::Read, path::Path}; /// The default directory filter. pub fn filter_dirs(path: &Path) -> bool { @@ -33,23 +33,26 @@ pub fn filter_dirs(path: &Path) -> bool { skip.iter().any(|p| path.ends_with(p)) } -pub fn walk_many( - paths: &[&Path], +/// Filter for only files that end in `.rs`. +pub fn filter_not_rust(path: &Path) -> bool { + path.extension() != Some(OsStr::new("rs")) && !path.is_dir() +} + +pub fn walk( + path: &Path, skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str), ) { - for path in paths { - walk(path, skip.clone(), f); - } + walk_many(&[path], skip, f); } -pub fn walk( - path: &Path, - skip: impl Send + Sync + 'static + Fn(&Path) -> bool, +pub fn walk_many( + paths: &[&Path], + skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str), ) { let mut contents = Vec::new(); - walk_no_read(path, skip, &mut |entry| { + walk_no_read(paths, skip, &mut |entry| { contents.clear(); let mut file = t!(File::open(entry.path()), entry.path()); t!(file.read_to_end(&mut contents), entry.path()); @@ -62,11 +65,14 @@ pub fn walk( } pub(crate) fn walk_no_read( - path: &Path, + paths: &[&Path], skip: impl Send + Sync + 'static + Fn(&Path) -> bool, f: &mut dyn FnMut(&DirEntry), ) { - let mut walker = ignore::WalkBuilder::new(path); + let mut walker = ignore::WalkBuilder::new(paths[0]); + for path in &paths[1..] { + walker.add(path); + } let walker = walker.filter_entry(move |e| !skip(e.path())); for entry in walker.build() { if let Ok(entry) = entry { diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs index 0b0b890b2c9..39909d7abfd 100644 --- a/tests/codegen/inherit_overflow.rs +++ b/tests/codegen/inherit_overflow.rs @@ -4,7 +4,7 @@ //[NOASSERT] compile-flags: -Coverflow-checks=off // CHECK-LABEL: define{{.*}} @assertion -// ASSERT: call void @_ZN4core9panicking5panic17h +// ASSERT: call void @{{.*4core9panicking5panic}} // NOASSERT: ret i8 0 #[no_mangle] pub fn assertion() -> u8 { diff --git a/tests/incremental/auxiliary/circular-dependencies-aux.rs b/tests/incremental/auxiliary/circular-dependencies-aux.rs new file mode 100644 index 00000000000..0e74eb1b2f2 --- /dev/null +++ b/tests/incremental/auxiliary/circular-dependencies-aux.rs @@ -0,0 +1,10 @@ +// edition: 2021 +// compile-flags: --crate-type lib --extern circular_dependencies={{build-base}}/circular-dependencies/libcircular_dependencies.rmeta --emit dep-info,metadata + +use circular_dependencies::Foo; + +pub fn consume_foo(_: Foo) {} + +pub fn produce_foo() -> Foo { + Foo +} diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs new file mode 100644 index 00000000000..10673066a9d --- /dev/null +++ b/tests/incremental/circular-dependencies.rs @@ -0,0 +1,37 @@ +// ignore-tidy-linelength +// revisions: cpass1 cfail2 +// edition: 2021 +// [cpass1] compile-flags: --crate-type lib --emit dep-info,metadata +// [cfail2] aux-build: circular-dependencies-aux.rs +// [cfail2] compile-flags: --test --extern aux={{build-base}}/circular-dependencies/auxiliary/libcircular_dependencies_aux.rmeta -L dependency={{build-base}}/circular-dependencies + +pub struct Foo; +//[cfail2]~^ NOTE `Foo` is defined in the current crate +//[cfail2]~| NOTE `Foo` is defined in the current crate +//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies` +//[cfail2]~| NOTE `circular_dependencies::Foo` is defined in crate `circular_dependencies` + +pub fn consume_foo(_: Foo) {} +//[cfail2]~^ NOTE function defined here + +pub fn produce_foo() -> Foo { + Foo +} + +#[test] +fn test() { + aux::consume_foo(produce_foo()); + //[cfail2]~^ ERROR mismatched types [E0308] + //[cfail2]~| NOTE expected `circular_dependencies::Foo`, found `Foo` + //[cfail2]~| NOTE arguments to this function are incorrect + //[cfail2]~| NOTE `Foo` and `circular_dependencies::Foo` have similar names, but are actually distinct types + //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations + //[cfail2]~| NOTE function defined here + + consume_foo(aux::produce_foo()); + //[cfail2]~^ ERROR mismatched types [E0308] + //[cfail2]~| NOTE expected `Foo`, found `circular_dependencies::Foo` + //[cfail2]~| NOTE arguments to this function are incorrect + //[cfail2]~| NOTE `circular_dependencies::Foo` and `Foo` have similar names, but are actually distinct types + //[cfail2]~| NOTE the crate `circular_dependencies` is compiled multiple times, possibly with different configurations +} diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir index 391b00effac..3884d29db41 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir @@ -4,21 +4,13 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _4: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _5: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _6: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _7: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 bb0: { - goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + goto -> bb8; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb1: { @@ -30,72 +22,34 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () { } bb3 (cleanup): { - _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _4 = &raw mut (*_1)[_3]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop((*_4)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb4 (cleanup): { - _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _6) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _5 = Eq(_3, _2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + switchInt(move _5) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb5: { - _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _6 = &raw mut (*_1)[_3]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + drop((*_6)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb6: { - _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _8) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _7 = Eq(_3, _2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + switchInt(move _7) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb7: { - _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _2 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } bb8: { goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 } - - bb9 (cleanup): { - _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb10 (cleanup): { - _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _12) -> [0: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb11: { - _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb12: { - _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _14) -> [0: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb13: { - _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = move _15 as *mut std::string::String (PtrToPtr); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb14: { - goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb15: { - _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _2) -> [0: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } } diff --git a/tests/ui/async-await/async-trait-fn.current.stderr b/tests/ui/async-await/async-trait-fn.current.stderr new file mode 100644 index 00000000000..7ccf2f2301d --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.current.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.next.stderr b/tests/ui/async-await/async-trait-fn.next.stderr new file mode 100644 index 00000000000..7ccf2f2301d --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.next.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.rs b/tests/ui/async-await/async-trait-fn.rs index e2062e82725..04123badb53 100644 --- a/tests/ui/async-await/async-trait-fn.rs +++ b/tests/ui/async-await/async-trait-fn.rs @@ -1,4 +1,5 @@ // edition:2018 + trait T { async fn foo() {} //~ ERROR functions in traits cannot be declared `async` async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` diff --git a/tests/ui/async-await/async-trait-fn.stderr b/tests/ui/async-await/async-trait-fn.stderr index afbe25cf7ab..68ebe3507ac 100644 --- a/tests/ui/async-await/async-trait-fn.stderr +++ b/tests/ui/async-await/async-trait-fn.stderr @@ -1,5 +1,5 @@ error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:3:5 + --> $DIR/async-trait-fn.rs:4:5 | LL | async fn foo() {} | -----^^^^^^^^^ @@ -12,7 +12,7 @@ LL | async fn foo() {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:4:5 + --> $DIR/async-trait-fn.rs:5:5 | LL | async fn bar(&self) {} | -----^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | async fn bar(&self) {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:5:5 + --> $DIR/async-trait-fn.rs:6:5 | LL | async fn baz() { | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr index ba918eb28de..c47b99e657e 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr @@ -1,5 +1,5 @@ error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:3:1 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -8,7 +8,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:5:12 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 | LL | fn baz() { async fn foo() {} } | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -17,7 +17,7 @@ LL | fn baz() { async fn foo() {} } = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:7:1 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 | LL | async fn async_baz() { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -26,7 +26,7 @@ LL | async fn async_baz() { = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:8:5 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -35,7 +35,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:14:5 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -44,7 +44,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -53,7 +53,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:36:9 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -62,7 +62,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:26:9 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -71,7 +71,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:31:13 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -80,7 +80,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr new file mode 100644 index 00000000000..c47b99e657e --- /dev/null +++ b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr @@ -0,0 +1,98 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 + | +LL | fn baz() { async fn foo() {} } + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 + | +LL | async fn async_baz() { + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0670, E0706. +For more information about an error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.rs b/tests/ui/async-await/edition-deny-async-fns-2015.rs index 6bd6d879a4a..d4c30dc9d82 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.rs +++ b/tests/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,4 +1,6 @@ // edition:2015 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr index 61a826258d0..2142ee232ca 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.stderr +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/async-default-fn-overridden.rs:4:12 + --> $DIR/async-default-fn-overridden.rs:6:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr new file mode 100644 index 00000000000..2142ee232ca --- /dev/null +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/async-default-fn-overridden.rs:6:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs index 0fd1a2703db..dd1af93d706 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs @@ -1,5 +1,7 @@ // run-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr index f1f0d7e5907..780da068962 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.current.stderr @@ -1,33 +1,33 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics-and-bounds.rs:12:18 + --> $DIR/async-generics-and-bounds.rs:14:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics-and-bounds.rs:12:18 + --> $DIR/async-generics-and-bounds.rs:14:18 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics-and-bounds.rs:12:28 + --> $DIR/async-generics-and-bounds.rs:14:28 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr new file mode 100644 index 00000000000..780da068962 --- /dev/null +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.next.stderr @@ -0,0 +1,37 @@ +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics-and-bounds.rs:14:18 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics-and-bounds.rs:14:18 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics-and-bounds.rs:14:28 + | +LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0311`. diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs index a73d55adfec..146e74ec2d0 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs @@ -1,6 +1,8 @@ // check-fail // known-bug: #102682 // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.current.stderr index 2f05564564c..04e1ab6d769 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.current.stderr @@ -1,33 +1,33 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics.rs:9:18 + --> $DIR/async-generics.rs:11:18 | LL | async fn foo(&self) -> &(T, U); | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/async-generics.rs:9:18 + --> $DIR/async-generics.rs:11:18 | LL | async fn foo(&self) -> &(T, U); | ^^^^^ note: ...so that the reference type `&(T, U)` does not outlive the data it points at - --> $DIR/async-generics.rs:9:28 + --> $DIR/async-generics.rs:11:28 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics.next.stderr b/tests/ui/async-await/in-trait/async-generics.next.stderr new file mode 100644 index 00000000000..04e1ab6d769 --- /dev/null +++ b/tests/ui/async-await/in-trait/async-generics.next.stderr @@ -0,0 +1,37 @@ +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics.rs:11:18 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/async-generics.rs:11:18 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^ +note: ...so that the reference type `&(T, U)` does not outlive the data it points at + --> $DIR/async-generics.rs:11:28 + | +LL | async fn foo(&self) -> &(T, U); + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0311`. diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs index 67000e5770e..507500abf4e 100644 --- a/tests/ui/async-await/in-trait/async-generics.rs +++ b/tests/ui/async-await/in-trait/async-generics.rs @@ -1,6 +1,8 @@ // check-fail // known-bug: #102682 // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/generics-mismatch.current.stderr b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr new file mode 100644 index 00000000000..be23384e049 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.next.stderr b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr new file mode 100644 index 00000000000..be23384e049 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs new file mode 100644 index 00000000000..fc29783c0e3 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -0,0 +1,15 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + async fn foo<T>(); +} + +impl Foo for () { + async fn foo<const N: usize>() {} + //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053] +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr new file mode 100644 index 00000000000..3518aa05cec --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:11:18 + | +LL | trait Foo { + | --- +LL | async fn foo<T>(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo<const N: usize>() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr index b8d83d0f28a..a5efc757156 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr +++ b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/return-type-suggestion.rs:3:12 + --> $DIR/return-type-suggestion.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/return-type-suggestion.rs:8:9 + --> $DIR/return-type-suggestion.rs:10:9 | LL | Ok(()) | ^^^^^^- help: consider using a semicolon here: `;` diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr new file mode 100644 index 00000000000..a5efc757156 --- /dev/null +++ b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr @@ -0,0 +1,23 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/return-type-suggestion.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/return-type-suggestion.rs:10:9 + | +LL | Ok(()) + | ^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs index 3446761d119..3de66306d9a 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.rs +++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr index 8672e79b3e8..463a37d7e3d 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -22,7 +22,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -34,7 +34,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -94,7 +94,7 @@ LL | let _ = [0; bar::<N>()]; | = help: try adding a `where` bound using this expression: `where [(); bar::<N>()]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -106,7 +106,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -134,7 +134,7 @@ LL | let _ = Foo::<{ bar::<N>() }>; | = help: try adding a `where` bound using this expression: `where [(); { bar::<N>() }]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -146,7 +146,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -160,3 +160,4 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 16 previous errors +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index f1353aa9943..a7bd9c62b0e 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -216,7 +216,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: [u8; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -228,7 +228,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -251,7 +251,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: Foo<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -263,7 +263,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -294,7 +294,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = [0; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -306,7 +306,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -329,7 +329,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = Foo::<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -341,7 +341,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -355,5 +355,5 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 36 previous errors -Some errors have detailed explanations: E0658, E0747. +Some errors have detailed explanations: E0658, E0747, E0794. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr index d681ecf25e8..05c025cc169 100644 --- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/box-coerce-span-in-default.rs:3:12 + --> $DIR/box-coerce-span-in-default.rs:5:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr new file mode 100644 index 00000000000..05c025cc169 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box-coerce-span-in-default.rs:5:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs index a4d483dee7a..163bb4fcf77 100644 --- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr index cc3bdf0e571..85450e3b0a0 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/default-body-type-err-2.rs:8:9 + --> $DIR/default-body-type-err-2.rs:10:9 | LL | 42 | ^^- help: try using a conversion method: `.to_string()` diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr new file mode 100644 index 00000000000..85450e3b0a0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.next.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/default-body-type-err-2.rs:10:9 + | +LL | 42 + | ^^- help: try using a conversion method: `.to_string()` + | | + | expected `String`, found integer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs index 45ae2b8ad3a..62323776310 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![allow(incomplete_features)] #![feature(async_fn_in_trait)] diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr index 4742eb37d3e..c949168a377 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.current.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` - --> $DIR/default-body-type-err.rs:7:22 + --> $DIR/default-body-type-err.rs:10:22 | LL | fn lol(&self) -> impl Deref<Target = String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr new file mode 100644 index 00000000000..c949168a377 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.next.stderr @@ -0,0 +1,12 @@ +error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` + --> $DIR/default-body-type-err.rs:10:22 + | +LL | fn lol(&self) -> impl Deref<Target = String> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` +LL | +LL | &1i32 + | ----- return type was inferred to be `&i32` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs index ac9baf91cae..9bd5b777989 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![allow(incomplete_features)] #![feature(return_position_impl_trait_in_trait)] diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr index b5fc9d44d36..3c24eff9ae3 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr @@ -1,11 +1,11 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/default-body-with-rpit.rs:11:9 + --> $DIR/default-body-with-rpit.rs:13:9 | LL | "" | ^^ expected `impl Debug`, got `&'static str` | note: previous use here - --> $DIR/default-body-with-rpit.rs:10:39 + --> $DIR/default-body-with-rpit.rs:12:39 | LL | async fn baz(&self) -> impl Debug { | _______________________________________^ @@ -14,7 +14,7 @@ LL | | } | |_____^ error[E0720]: cannot resolve opaque type - --> $DIR/default-body-with-rpit.rs:10:28 + --> $DIR/default-body-with-rpit.rs:12:28 | LL | async fn baz(&self) -> impl Debug { | ^^^^^^^^^^ cannot resolve opaque type diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr new file mode 100644 index 00000000000..3c24eff9ae3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr @@ -0,0 +1,24 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/default-body-with-rpit.rs:13:9 + | +LL | "" + | ^^ expected `impl Debug`, got `&'static str` + | +note: previous use here + --> $DIR/default-body-with-rpit.rs:12:39 + | +LL | async fn baz(&self) -> impl Debug { + | _______________________________________^ +LL | | "" +LL | | } + | |_____^ + +error[E0720]: cannot resolve opaque type + --> $DIR/default-body-with-rpit.rs:12:28 + | +LL | async fn baz(&self) -> impl Debug { + | ^^^^^^^^^^ cannot resolve opaque type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs index 0558d95128f..6bcc7b9ef95 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -1,5 +1,7 @@ // edition:2021 // known-bug: #108304 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/default-body.rs b/tests/ui/impl-trait/in-trait/default-body.rs index b0baf5bb10d..ab6a51c6bcb 100644 --- a/tests/ui/impl-trait/in-trait/default-body.rs +++ b/tests/ui/impl-trait/in-trait/default-body.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr index 5e18605aa4c..7bb79911f56 100644 --- a/tests/ui/impl-trait/in-trait/default-method-constraint.stderr +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-method-constraint.rs:5:12 + --> $DIR/default-method-constraint.rs:7:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr new file mode 100644 index 00000000000..7bb79911f56 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default-method-constraint.rs:7:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.rs b/tests/ui/impl-trait/in-trait/default-method-constraint.rs index 8c50cc29586..e85fe3c8626 100644 --- a/tests/ui/impl-trait/in-trait/default-method-constraint.rs +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next // This didn't work in the previous default RPITIT method hack attempt diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr index aa5492d285e..653016cf009 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` - --> $DIR/doesnt-satisfy.rs:9:17 + --> $DIR/doesnt-satisfy.rs:12:17 | LL | fn bar() -> () {} | ^^ `()` cannot be formatted with the default formatter @@ -7,7 +7,7 @@ LL | fn bar() -> () {} = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::bar::{opaque#0}` - --> $DIR/doesnt-satisfy.rs:5:22 + --> $DIR/doesnt-satisfy.rs:8:22 | LL | fn bar() -> impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr new file mode 100644 index 00000000000..bbfa089ceef --- /dev/null +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr @@ -0,0 +1,17 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/doesnt-satisfy.rs:12:17 + | +LL | fn bar() -> () {} + | ^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `Foo::{opaque#0}` + --> $DIR/doesnt-satisfy.rs:8:22 + | +LL | fn bar() -> impl std::fmt::Display; + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs index bb4e0d44f3e..fcd0b51eea4 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr index cd42683e022..310edbcb6cd 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/generics-mismatch.rs:11:12 + --> $DIR/generics-mismatch.rs:14:12 | LL | fn bar(&self) -> impl Sized; | - expected 0 type parameters diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr new file mode 100644 index 00000000000..310edbcb6cd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/generics-mismatch.rs:14:12 + | +LL | fn bar(&self) -> impl Sized; + | - expected 0 type parameters +... +LL | fn bar<T>(&self) {} + | ^ found 1 type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs index cc0fc720ebb..9259ca193d1 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr index 87219941d91..cac9a29f644 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:20:9 + --> $DIR/issue-102571.rs:23:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` diff --git a/tests/ui/impl-trait/in-trait/issue-102571.next.stderr b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr new file mode 100644 index 00000000000..cac9a29f644 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/issue-102571.next.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-102571.rs:23:9 + | +LL | let () = t.bar(); + | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + | | + | expected associated type, found `()` + | + = note: expected associated type `impl Deref<Target = impl std::fmt::Display + ?Sized>` + found unit type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index 61c91e64417..f0ddab5e7f2 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr index dc621d6b8a8..f48e7a1ed14 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.current.stderr @@ -1,5 +1,5 @@ error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/specialization-broken.rs:16:22 + --> $DIR/specialization-broken.rs:19:22 | LL | default impl<U> Foo for U | - this type parameter @@ -11,7 +11,7 @@ LL | fn bar(&self) -> U { | help: change the output type to match the trait: `impl Sized` | note: type in trait - --> $DIR/specialization-broken.rs:9:22 + --> $DIR/specialization-broken.rs:12:22 | LL | fn bar(&self) -> impl Sized; | ^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | fn bar(&self) -> impl Sized; found signature `fn(&U) -> U` error: method with return-position `impl Trait` in trait cannot be specialized - --> $DIR/specialization-broken.rs:16:5 + --> $DIR/specialization-broken.rs:19:5 | LL | fn bar(&self) -> U { | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr new file mode 100644 index 00000000000..f48e7a1ed14 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/specialization-broken.next.stderr @@ -0,0 +1,31 @@ +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/specialization-broken.rs:19:22 + | +LL | default impl<U> Foo for U + | - this type parameter +... +LL | fn bar(&self) -> U { + | ^ + | | + | expected associated type, found type parameter `U` + | help: change the output type to match the trait: `impl Sized` + | +note: type in trait + --> $DIR/specialization-broken.rs:12:22 + | +LL | fn bar(&self) -> impl Sized; + | ^^^^^^^^^^ + = note: expected signature `fn(&U) -> impl Sized` + found signature `fn(&U) -> U` + +error: method with return-position `impl Trait` in trait cannot be specialized + --> $DIR/specialization-broken.rs:19:5 + | +LL | fn bar(&self) -> U { + | ^^^^^^^^^^^^^^^^^^ + | + = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 2fcffdf3f9a..658d0709717 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + // FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not. // But we fixed an ICE anyways. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr index 03cc4c2b93b..8392f26e7c8 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:9:22 + --> $DIR/wf-bounds.rs:11:22 | LL | fn nya() -> impl Wf<Vec<[u8]>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,14 +9,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:12:23 + --> $DIR/wf-bounds.rs:14:23 | LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wf` - --> $DIR/wf-bounds.rs:6:10 + --> $DIR/wf-bounds.rs:8:10 | LL | trait Wf<T> {} | ^ required by this bound in `Wf` diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr new file mode 100644 index 00000000000..8392f26e7c8 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/wf-bounds.next.stderr @@ -0,0 +1,30 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:11:22 + | +LL | fn nya() -> impl Wf<Vec<[u8]>>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/wf-bounds.rs:14:23 + | +LL | fn nya2() -> impl Wf<[u8]>; + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `Wf` + --> $DIR/wf-bounds.rs:8:10 + | +LL | trait Wf<T> {} + | ^ required by this bound in `Wf` +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Wf<T: ?Sized> {} + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs index 2c71583b312..39f41275315 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.rs +++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs @@ -1,4 +1,6 @@ // issue #101663 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed index 0e60c73b67a..0f688fa2823 100644 --- a/tests/ui/imports/issue-99695-b.fixed +++ b/tests/ui/imports/issue-99695-b.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style)] +#![allow(unused, nonstandard_style, useless_anonymous_reexport)] mod m { mod p { diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs index 031443a1f5d..b433997e53f 100644 --- a/tests/ui/imports/issue-99695-b.rs +++ b/tests/ui/imports/issue-99695-b.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style)] +#![allow(unused, nonstandard_style, useless_anonymous_reexport)] mod m { mod p { diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed index 6bf228b23aa..17ff409324e 100644 --- a/tests/ui/imports/issue-99695.fixed +++ b/tests/ui/imports/issue-99695.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style)] +#![allow(unused, nonstandard_style, useless_anonymous_reexport)] mod m { #[macro_export] macro_rules! nu { diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs index f7199f1497a..b8979bcb734 100644 --- a/tests/ui/imports/issue-99695.rs +++ b/tests/ui/imports/issue-99695.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style)] +#![allow(unused, nonstandard_style, useless_anonymous_reexport)] mod m { #[macro_export] macro_rules! nu { diff --git a/tests/ui/late-bound-lifetimes/issue-80618.rs b/tests/ui/late-bound-lifetimes/issue-80618.rs new file mode 100644 index 00000000000..6aa8ff461a9 --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.rs @@ -0,0 +1,8 @@ +fn foo<'a>(x: &'a str) -> &'a str { + x +} + +fn main() { + let _ = foo::<'static>; +//~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present [E0794] +} diff --git a/tests/ui/late-bound-lifetimes/issue-80618.stderr b/tests/ui/late-bound-lifetimes/issue-80618.stderr new file mode 100644 index 00000000000..cf7423fc16f --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.stderr @@ -0,0 +1,15 @@ +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-80618.rs:6:19 + | +LL | let _ = foo::<'static>; + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/issue-80618.rs:1:8 + | +LL | fn foo<'a>(x: &'a str) -> &'a str { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index 1c122f42e59..0ae68ad04f7 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -25,4 +25,9 @@ fn d<const C: S>() {} //~^ ERROR missing lifetime specifier //~| ERROR `S<'_>` is forbidden as the type of a const generic parameter +trait Foo<'a> {} +struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; +//~^ ERROR use of non-static lifetime `'a` in const generic +//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter + fn main() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 68f4fce0178..20163d289b1 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -9,6 +9,14 @@ help: consider introducing a named lifetime parameter LL | fn d<'a, const C: S<'a>>() {} | +++ ++++ +error[E0771]: use of non-static lifetime `'a` in const generic + --> $DIR/unusual-rib-combinations.rs:29:22 + | +LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; + | ^^ + | + = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052> + error[E0214]: parenthesized type parameters may only be used with a `Fn` trait --> $DIR/unusual-rib-combinations.rs:7:16 | @@ -55,7 +63,16 @@ LL | fn d<const C: S>() {} = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: aborting due to 7 previous errors +error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter + --> $DIR/unusual-rib-combinations.rs:29:21 + | +LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0106, E0214, E0308. +Some errors have detailed explanations: E0106, E0214, E0308, E0771. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs new file mode 100644 index 00000000000..5d56ae6f969 --- /dev/null +++ b/tests/ui/lint/anonymous-reexport.rs @@ -0,0 +1,21 @@ +#![deny(useless_anonymous_reexport)] +#![crate_type = "rlib"] + +mod my_mod { + pub trait Foo {} + pub type TyFoo = dyn Foo; + pub struct Bar; + pub type TyBar = Bar; +} + +pub use self::my_mod::Foo as _; +pub use self::my_mod::TyFoo as _; +pub use self::my_mod::Bar as _; //~ ERROR +pub use self::my_mod::TyBar as _; //~ ERROR +pub use self::my_mod::{Bar as _}; //~ ERROR +pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR +pub use self::my_mod::{Bar as _, TyBar as _}; +//~^ ERROR +//~| ERROR +#[allow(unused_imports)] +use self::my_mod::TyBar as _; diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr new file mode 100644 index 00000000000..f4f8b41c417 --- /dev/null +++ b/tests/ui/lint/anonymous-reexport.stderr @@ -0,0 +1,55 @@ +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:13:1 + | +LL | pub use self::my_mod::Bar as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `struct` +note: the lint level is defined here + --> $DIR/anonymous-reexport.rs:1:9 + | +LL | #![deny(useless_anonymous_reexport)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:14:1 + | +LL | pub use self::my_mod::TyBar as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `type alias` + +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:15:24 + | +LL | pub use self::my_mod::{Bar as _}; + | ^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `struct` + +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:16:24 + | +LL | pub use self::my_mod::{Bar as _, Foo as _}; + | ^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `struct` + +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:17:24 + | +LL | pub use self::my_mod::{Bar as _, TyBar as _}; + | ^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `struct` + +error: useless anonymous re-export + --> $DIR/anonymous-reexport.rs:17:34 + | +LL | pub use self::my_mod::{Bar as _, TyBar as _}; + | ^^^^^^^^^^ + | + = note: only anonymous re-exports of traits are useful, this is a `type alias` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/macros/issue-109237.rs b/tests/ui/macros/issue-109237.rs new file mode 100644 index 00000000000..86a193c9e44 --- /dev/null +++ b/tests/ui/macros/issue-109237.rs @@ -0,0 +1,7 @@ +macro_rules! statement { + () => {;}; //~ ERROR expected expression +} + +fn main() { + let _ = statement!(); +} diff --git a/tests/ui/macros/issue-109237.stderr b/tests/ui/macros/issue-109237.stderr new file mode 100644 index 00000000000..d125cff63ea --- /dev/null +++ b/tests/ui/macros/issue-109237.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `;` + --> $DIR/issue-109237.rs:2:12 + | +LL | () => {;}; + | ^ expected expression +... +LL | let _ = statement!(); + | ------------ in this macro invocation + | + = note: the macro call doesn't expand to an expression, but it can expand to a statement + = note: this error originates in the macro `statement` (in Nightly builds, run with -Z macro-backtrace for more info) +help: surround the macro invocation with `{}` to interpret the expansion as a statement + | +LL | let _ = { statement!(); }; + | ~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr index 34526256f99..645d8b8d14a 100644 --- a/tests/ui/methods/method-call-lifetime-args-fail.stderr +++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr @@ -30,7 +30,7 @@ note: method defined here, with 2 lifetime parameters: `'a`, `'b` LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } | ^^^^^ -- -- -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:27:15 | LL | S::late::<'static>(S, &0, &0); @@ -42,7 +42,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:29:15 | LL | S::late::<'static, 'static>(S, &0, &0); @@ -54,7 +54,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:31:15 | LL | S::late::<'static, 'static, 'static>(S, &0, &0); @@ -66,7 +66,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:34:21 | LL | S::late_early::<'static, 'static>(S, &0); @@ -78,7 +78,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:36:21 | LL | S::late_early::<'static, 'static, 'static>(S, &0); @@ -90,7 +90,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:40:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -102,7 +102,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:42:24 | LL | S::late_implicit::<'static, 'static>(S, &0, &0); @@ -114,7 +114,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:44:24 | LL | S::late_implicit::<'static, 'static, 'static>(S, &0, &0); @@ -126,7 +126,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:47:30 | LL | S::late_implicit_early::<'static, 'static>(S, &0); @@ -138,7 +138,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:49:30 | LL | S::late_implicit_early::<'static, 'static, 'static>(S, &0); @@ -150,7 +150,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:52:35 | LL | S::late_implicit_self_early::<'static, 'static>(&S); @@ -162,7 +162,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:54:35 | LL | S::late_implicit_self_early::<'static, 'static, 'static>(&S); @@ -174,7 +174,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:57:28 | LL | S::late_unused_early::<'static, 'static>(S); @@ -186,7 +186,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:59:28 | LL | S::late_unused_early::<'static, 'static, 'static>(S); @@ -232,4 +232,5 @@ LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0794. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/methods/method-call-lifetime-args.stderr b/tests/ui/methods/method-call-lifetime-args.stderr index 64ae79e9bb2..b215d583217 100644 --- a/tests/ui/methods/method-call-lifetime-args.stderr +++ b/tests/ui/methods/method-call-lifetime-args.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:9:15 | LL | S::late::<'static>(S, &0, &0); @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:11:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -24,3 +24,4 @@ LL | fn late_implicit(self, _: &u8, _: &u8) {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs new file mode 100644 index 00000000000..8804186ee1a --- /dev/null +++ b/tests/ui/stability-attribute/auxiliary/similar-unstable-method.rs @@ -0,0 +1,13 @@ +#![feature(staged_api)] +#![stable(feature = "libfoo", since = "1.0.0")] + +#[unstable(feature = "foo", reason = "...", issue = "none")] +pub fn foo() {} + +#[stable(feature = "libfoo", since = "1.0.0")] +pub struct Foo; + +impl Foo { + #[unstable(feature = "foo", reason = "...", issue = "none")] + pub fn foo(&self) {} +} diff --git a/tests/ui/stability-attribute/issue-109177.rs b/tests/ui/stability-attribute/issue-109177.rs new file mode 100644 index 00000000000..6d052779c6d --- /dev/null +++ b/tests/ui/stability-attribute/issue-109177.rs @@ -0,0 +1,13 @@ +// aux-build: similar-unstable-method.rs + +extern crate similar_unstable_method; + +fn main() { + // FIXME: this function should not suggest the `foo` function. + similar_unstable_method::foo1(); + //~^ ERROR cannot find function `foo1` in crate `similar_unstable_method` [E0425] + + let foo = similar_unstable_method::Foo; + foo.foo1(); + //~^ ERROR no method named `foo1` found for struct `Foo` in the current scope [E0599] +} diff --git a/tests/ui/stability-attribute/issue-109177.stderr b/tests/ui/stability-attribute/issue-109177.stderr new file mode 100644 index 00000000000..9c2ac591ace --- /dev/null +++ b/tests/ui/stability-attribute/issue-109177.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find function `foo1` in crate `similar_unstable_method` + --> $DIR/issue-109177.rs:7:30 + | +LL | similar_unstable_method::foo1(); + | ^^^^ help: a function with a similar name exists: `foo` + | + ::: $DIR/auxiliary/similar-unstable-method.rs:5:1 + | +LL | pub fn foo() {} + | ------------ similarly named function `foo` defined here + +error[E0599]: no method named `foo1` found for struct `Foo` in the current scope + --> $DIR/issue-109177.rs:11:9 + | +LL | foo.foo1(); + | ^^^^ method not found in `Foo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.rs b/tests/ui/suggestions/bad-infer-in-trait-impl.rs new file mode 100644 index 00000000000..87db2636fb2 --- /dev/null +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.rs @@ -0,0 +1,10 @@ +trait Foo { + fn bar(); +} + +impl Foo for () { + fn bar(s: _) {} + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions +} + +fn main() {} diff --git a/tests/ui/suggestions/bad-infer-in-trait-impl.stderr b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr new file mode 100644 index 00000000000..418690ff85f --- /dev/null +++ b/tests/ui/suggestions/bad-infer-in-trait-impl.stderr @@ -0,0 +1,14 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/bad-infer-in-trait-impl.rs:6:15 + | +LL | fn bar(s: _) {} + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn bar<T>(s: T) {} + | +++ ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.rs b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs new file mode 100644 index 00000000000..459b94f943b --- /dev/null +++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.rs @@ -0,0 +1,11 @@ +// edition: 2021 + +// Make sure we don't ICE when suggesting a return type +// for an async fn that has late-bound vars... + +async fn ice(_: &i32) { + true + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr new file mode 100644 index 00000000000..bff864b222b --- /dev/null +++ b/tests/ui/suggestions/suggest-ret-on-async-w-late.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/suggest-ret-on-async-w-late.rs:7:5 + | +LL | async fn ice(_: &i32) { + | - help: try adding a return type: `-> bool` +LL | true + | ^^^^ expected `()`, found `bool` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs new file mode 100644 index 00000000000..50f0152e904 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn f() +where + for<B> B::Item: Send, + //~^ ERROR ambiguous associated type +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr new file mode 100644 index 00000000000..be6955c111e --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr @@ -0,0 +1,18 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-assoc-item.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0223]: ambiguous associated type + --> $DIR/missing-assoc-item.rs:6:12 + | +LL | for<B> B::Item: Send, + | ^^^^^^^ help: use the fully-qualified path: `<B as IntoIterator>::Item` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index a450dbb82d1..e6f7dc410b6 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -228,5 +228,4 @@ fn evens_squared(n: usize) -> _ { const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); //~^ ERROR the trait bound -//~| ERROR the trait bound //~| ERROR the placeholder diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index bc6c9fd0779..9144ab9e3a6 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -437,19 +437,6 @@ LL | fn evens_squared(n: usize) -> _ { | not allowed in type signatures | help: replace with an appropriate return type: `impl Iterator<Item = usize>` -error[E0277]: the trait bound `std::ops::Range<{integer}>: Iterator` is not satisfied - --> $DIR/typeck_type_placeholder_item.rs:229:22 - | -LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); - | ^^^^^^ `std::ops::Range<{integer}>` is not an iterator - | - = help: the trait `~const Iterator` is not implemented for `std::ops::Range<{integer}>` -note: the trait `Iterator` is implemented for `std::ops::Range<{integer}>`, but that implementation is not `const` - --> $DIR/typeck_type_placeholder_item.rs:229:14 - | -LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); - | ^^^^^^^ - error[E0277]: the trait bound `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>: Iterator` is not satisfied --> $DIR/typeck_type_placeholder_item.rs:229:45 | @@ -677,7 +664,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error: aborting due to 73 previous errors +error: aborting due to 72 previous errors Some errors have detailed explanations: E0121, E0277, E0282, E0403. For more information about an error, try `rustc --explain E0121`. |
