diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 70cb6dfd66f27..67fd6d793e0b1 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 6cb9e163b404e..64961baf272f4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(callee), + ty::EarlyBinder::bind(callee), ); let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 51393a5d774dc..0041400320260 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance.subst_mir_and_normalize_erasing_regions( self.cx.tcx(), ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 9195ae163bc61..91ccdef7215c2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -497,7 +497,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .try_subst_mir_and_normalize_erasing_regions( *self.tcx, self.param_env, - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) .map_err(|_| err_inval!(TooGeneric)) } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index d9796e8ffe0b6..3d78ea9aa9ba1 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1280,7 +1280,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // params (and trait ref's late bound params). This logic is very similar to // `Predicate::subst_supertrait`, and it's no coincidence why. let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder::new(shifted_output).subst(tcx, substs); + let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs); let bound_vars = tcx.late_bound_vars(binding.hir_id); ty::Binder::bind_with_vars(subst_output, bound_vars) 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 be901b7236fdb..31b89525f15d4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -796,14 +796,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty::EarlyBinder::new(ty)); + collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder::new(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::bind(tcx.ty_error(reported))); } } } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 897e4135fa038..13d1abe2a6566 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder::new(tcx.param_env(adt_def_id)) + let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)) .subst(tcx, adt_to_impl_substs) .with_constness(tcx.constness(drop_impl_def_id)); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7295d1dc0fdc6..fff417fcb2909 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1407,7 +1407,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder::new(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder::bind(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e7a8fd8ffd79f..2f7d465839c4c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( @@ -1312,7 +1312,7 @@ fn impl_trait_ref( check_impl_constness(tcx, impl_.constness, ast_trait_ref), ) }) - .map(ty::EarlyBinder::new) + .map(ty::EarlyBinder::bind) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 03c8c59402e76..b92d561fb86a4 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds( 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 ty::EarlyBinder::new(opaque_type_bounds( + return ty::EarlyBinder::bind(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds( } _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder::new(bounds) + ty::EarlyBinder::bind(bounds) } pub(super) fn item_bounds( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 0b57d69658563..65ab00fda817a 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - return ty::EarlyBinder::new(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(tcx.ty_error_with_message( DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index d7f11d3fd9d38..7ce48fe1c012f 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { } } - ty::EarlyBinder::new(required_predicates) + ty::EarlyBinder::bind(required_predicates) }) } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index ced994aa6366e..71dca918fc5e1 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -74,7 +74,7 @@ pub(super) fn infer_predicates( if item_required_predicates.len() > item_predicates_len { predicates_added = true; global_inferred_outlives - .insert(item_did.to_def_id(), ty::EarlyBinder::new(item_required_predicates)); + .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 655ab94eb48d1..4389ad6ef2678 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -420,20 +420,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) { // Try suggesting `foo(a)` -> `a.foo()` if possible. - if let Some(ty) = - self.suggest_call_as_method( - &mut diag, - segment, - arg_exprs, - call_expr, - expected - ) - { - diag.emit(); - return ty; - } else { - diag.emit(); - } + self.suggest_call_as_method( + &mut diag, + segment, + arg_exprs, + call_expr, + expected + ); + diag.emit(); } let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); @@ -496,9 +490,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], call_expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - ) -> Option> { + ) { if let [callee_expr, rest @ ..] = arg_exprs { - let callee_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)?; + let Some(callee_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) else { + return; + }; // First, do a probe with `IsSuggestion(true)` to avoid emitting // any strange errors. If it's successful, then we'll do a true @@ -513,7 +509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::AllTraits, expected.only_has_type(self), ) else { - return None; + return; }; let pick = self.confirm_method( @@ -525,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment, ); if pick.illegal_sized_bound.is_some() { - return None; + return; } let up_to_rcvr_span = segment.ident.span.until(callee_expr.span); @@ -567,22 +563,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg, Applicability::MaybeIncorrect, ); - - // Let's check the method fully now - let return_ty = self.check_method_argument_types( - segment.ident.span, - call_expr, - Ok(pick.callee), - rest, - TupleArgumentsFlag::DontTupleArguments, - expected, - ); - - return Some(return_ty); } } - - None } fn report_invalid_callee( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8555c20204ad6..9ee967dc7a97e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -473,6 +473,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut custom_span_label = false; let static_candidates = &mut no_match_data.static_candidates; + + // `static_candidates` may have same candidates appended by + // inherent and extension, which may result in incorrect + // diagnostic. + static_candidates.dedup(); + if !static_candidates.is_empty() { err.note( "found the following associated functions; to be used as methods, \ diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d34a3afcba53a..e707ac41a050d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -304,6 +304,14 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + +# FIXME: we should ordinalize $valid_up_to when we add support for doing so +lint_invalid_from_utf8_unchecked = calls to `{$method}` with a invalid literal are undefined behavior + .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs new file mode 100644 index 0000000000000..3291286ad679b --- /dev/null +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -0,0 +1,118 @@ +use std::str::Utf8Error; + +use rustc_ast::{BorrowKind, LitKind}; +use rustc_hir::{Expr, ExprKind}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; + +use crate::lints::InvalidFromUtf8Diag; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_from_utf8_unchecked` lint checks for calls to + /// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #[allow(unused)] + /// unsafe { + /// std::str::from_utf8_unchecked(b"Ru\x82st"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating such a `str` would result in undefined behavior as per documentation + /// for `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`. + pub INVALID_FROM_UTF8_UNCHECKED, + Deny, + "using a non UTF-8 literal in `std::str::from_utf8_unchecked`" +} + +declare_lint! { + /// The `invalid_from_utf8` lint checks for calls to + /// `std::str::from_utf8` and `std::str::from_utf8_mut` + /// with an invalid UTF-8 literal. + /// + /// ### Example + /// + /// ```rust + /// # #[allow(unused)] + /// std::str::from_utf8(b"Ru\x82st"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to create such a `str` would always return an error as per documentation + /// for `std::str::from_utf8` and `std::str::from_utf8_mut`. + pub INVALID_FROM_UTF8, + Warn, + "using a non UTF-8 literal in `std::str::from_utf8`" +} + +declare_lint_pass!(InvalidFromUtf8 => [INVALID_FROM_UTF8_UNCHECKED, INVALID_FROM_UTF8]); + +impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) + && [sym::str_from_utf8, sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + { + let lint = |utf8_error: Utf8Error| { + let label = arg.span; + let method = diag_item.as_str().strip_prefix("str_").unwrap(); + let method = format!("std::str::{method}"); + let valid_up_to = utf8_error.valid_up_to(); + let is_unchecked_variant = diag_item.as_str().contains("unchecked"); + + cx.emit_spanned_lint( + if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + expr.span, + if is_unchecked_variant { + InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } + } else { + InvalidFromUtf8Diag::Checked { method, valid_up_to, label } + } + ) + }; + + match &arg.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => { + if let LitKind::ByteStr(bytes, _) = &lit + && let Err(utf8_error) = std::str::from_utf8(bytes) + { + lint(utf8_error); + } + }, + ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { + let elements = args.iter().map(|e|{ + match &e.kind { + ExprKind::Lit(Spanned { node: lit, .. }) => match lit { + LitKind::Byte(b) => Some(*b), + LitKind::Int(b, _) => Some(*b as u8), + _ => None + } + _ => None + } + }).collect::>>(); + + if let Some(elements) = elements + && let Err(utf8_error) = std::str::from_utf8(&elements) + { + lint(utf8_error); + } + } + _ => {} + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index dfddfe09ab3c1..c62109b298629 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -60,6 +60,7 @@ mod expect; mod for_loops_over_fallibles; pub mod hidden_unicode_codepoints; mod internal; +mod invalid_from_utf8; mod late; mod let_underscore; mod levels; @@ -102,6 +103,7 @@ use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; +use invalid_from_utf8::*; use let_underscore::*; use map_unit_fn::*; use methods::*; @@ -207,6 +209,7 @@ late_lint_methods!( HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, + InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6b4d01551ae9b..746abebeb375a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -699,6 +699,25 @@ pub struct ForgetCopyDiag<'a> { pub label: Span, } +// invalid_from_utf8.rs +#[derive(LintDiagnostic)] +pub enum InvalidFromUtf8Diag { + #[diag(lint_invalid_from_utf8_unchecked)] + Unchecked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, + #[diag(lint_invalid_from_utf8_checked)] + Checked { + method: String, + valid_up_to: usize, + #[label] + label: Span, + }, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 06fdc6fe03084..09e24e012afa3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -858,7 +858,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } else { tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) }; - ty::EarlyBinder::new(&*output) + ty::EarlyBinder::bind(&*output) } fn get_variant( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f2a7762f00386..c673eb5afc793 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1730,7 +1730,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::new(substs.as_closure().sig())); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 34e47de969c17..63cdba7f327f6 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn bound_return_ty(&self) -> ty::EarlyBinder> { - ty::EarlyBinder::new(self.local_decls[RETURN_PLACE].ty) + ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty) } /// Gets the location of the terminator for the given block. diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2b99fcad26758..e067d2a984fde 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder::new(tcx.adt_sized_constraint(self.did())) + ty::EarlyBinder::bind(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5fcbc4a9ed49a..aecb46556b041 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder::new(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 76a6a421282e1..30f92b91cb7a0 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -343,7 +343,7 @@ impl<'tcx> GenericPredicates<'tcx> { substs: SubstsRef<'tcx>, ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator { - EarlyBinder::new(self.predicates).subst_iter_copied(tcx, substs) + EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] @@ -358,7 +358,7 @@ impl<'tcx> GenericPredicates<'tcx> { } instantiated .predicates - .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::new(*p).subst(tcx, substs))); + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index b3cc27e3f7838..d48672b2baaee 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -158,7 +158,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option { match self { Self::ConstIsZero(c) => { - let c = ty::EarlyBinder::new(c).subst(tcx, substs); + let c = ty::EarlyBinder::bind(c).subst(tcx, substs); let pred = match c.kind().try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, @@ -167,7 +167,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(pred) } Self::GenericType(t) => { - Some(ty::EarlyBinder::new(t).subst(tcx, substs).inhabited_predicate(tcx)) + Some(ty::EarlyBinder::bind(t).subst(tcx, substs).inhabited_predicate(tcx)) } Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ac2144529b5aa..72341e656e29e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -764,7 +764,7 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder::new(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder::bind(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 68be9f83ba8bd..d19a7bcde79bc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { - ty::EarlyBinder::new(layout.field_tys[*field].ty).subst(tcx, self.substs) + ty::EarlyBinder::bind(layout.field_tys[*field].ty).subst(tcx, self.substs) }) }) } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8691a3070bcf6..8685a22d9ca88 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -545,7 +545,7 @@ impl<'tcx, T> !TypeFoldable> for ty::EarlyBinder {} impl<'tcx, T> !TypeVisitable> for ty::EarlyBinder {} impl EarlyBinder { - pub fn new(inner: T) -> EarlyBinder { + pub fn bind(inner: T) -> EarlyBinder { EarlyBinder(inner) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index dade50df5d962..311f63adc7f49 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> { .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder::new(decl.ty)) + .map(|decl| ty::EarlyBinder::bind(decl.ty)) } /// Normalizes all opaque types in the given value, replacing them diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 58374f6b3bd78..a00c77ccbcdc2 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -96,13 +96,13 @@ impl<'tcx> Value, DepKind> for Representability { impl<'tcx> Value, DepKind> for ty::EarlyBinder> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder::new(Ty::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) } } impl<'tcx> Value, DepKind> for ty::EarlyBinder>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder::new(ty::Binder::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) } } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index c0458126840da..b1c9c4acc40e4 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -83,7 +83,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite - let subst_ty = EarlyBinder::new(inner_ty).subst(self.tcx, substs_ref); + let subst_ty = EarlyBinder::bind(inner_ty).subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index e27d48fa8f65a..55b9f084c39f7 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -192,7 +192,7 @@ impl<'tcx> Inliner<'tcx> { let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - ty::EarlyBinder::new(callee_body.clone()), + ty::EarlyBinder::bind(callee_body.clone()), ) else { return Err("failed to normalize callee body"); }; @@ -455,7 +455,7 @@ impl<'tcx> Inliner<'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = callsite .callee - .subst_mir(self.tcx, ty::EarlyBinder::new(&place.ty(callee_body, tcx).ty)); + .subst_mir(self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); } @@ -790,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = self .instance - .subst_mir(tcx, ty::EarlyBinder::new(&place.ty(self.callee_body, tcx).ty)); + .subst_mir(tcx, ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) { self.cost += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::new(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 00842e9d66596..8a10445f8377e 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -47,7 +47,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions( tcx, param_env, - ty::EarlyBinder::new(substs), + ty::EarlyBinder::bind(substs), ) else { trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 522220f3d77c1..ae726dea94426 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = EarlyBinder::new(body.clone()).subst(tcx, substs); + let body = EarlyBinder::bind(body.clone()).subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); return body; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8874aa7d3ca9b..cefa64d27acba 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::new(value), + ty::EarlyBinder::bind(value), ) } } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 772f15201536c..f6a80b0431fc3 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let before_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder::new(before_feature_tys), + ty::EarlyBinder::bind(before_feature_tys), ); let after_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder::new(after_feature_tys), + ty::EarlyBinder::bind(after_feature_tys), ); let new_size = tcx diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 874d578fe1db3..1185563ea8063 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1454,6 +1454,10 @@ symbols! { stop_after_dataflow, store, str, + str_from_utf8, + str_from_utf8_mut, + str_from_utf8_unchecked, + str_from_utf8_unchecked_mut, str_split_whitespace, str_trim, str_trim_end, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 55901bfbde9cf..0a805e2422d40 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -274,7 +274,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); if !substs.is_empty() { - param_env = EarlyBinder::new(param_env).subst(self.tcx, substs); + param_env = EarlyBinder::bind(param_env).subst(self.tcx, substs); } match &mut impl_trait_ref { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0f84032d9ef6d..4b38687eebeef 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -487,7 +487,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI tcx, ObligationCause::dummy_with_span(*span), param_env, - ty::EarlyBinder::new(*pred).subst(tcx, impl_trait_ref.substs), + ty::EarlyBinder::bind(*pred).subst(tcx, impl_trait_ref.substs), ) }) }); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0be21156b6c96..9582479941b66 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>( if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = EarlyBinder::new(receiver_ty).subst(tcx, substs); + let result = EarlyBinder::bind(receiver_ty).subst(tcx, substs); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 0a1b1b10b0070..709c3f432e609 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -307,13 +307,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // there, but that needs some way to handle cycles. constraints .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); constraints .outlives - .extend(outlives.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); constraints .overflows - .extend(overflows.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); + .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).subst(tcx, substs))); } // Objects must be alive in order for their destructor diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 0925b3956de36..57b4183d33671 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -301,7 +301,7 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder::new(tcx.mk_opaque( + trait_assoc_ty.type_of(ty::EarlyBinder::bind(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index bb723c9997ac1..ce77df0df5dcf 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -419,7 +419,7 @@ pub fn thir_abstract_const( let root_span = body.exprs[body_id].span; - Ok(Some(ty::EarlyBinder::new(recurse_build(tcx, body, body_id, root_span)?))) + Ok(Some(ty::EarlyBinder::bind(recurse_build(tcx, body, body_id, root_span)?))) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0e5b23ca423ef..7015778e24b85 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -610,7 +610,7 @@ fn generator_layout<'tcx>( ) -> Result, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = cx.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder::new(ty).subst(tcx, substs); + let subst_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).subst(tcx, substs); let Some(info) = tcx.generator_layout(def_id) else { return Err(LayoutError::Unknown(ty)); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 075fde6ddb654..9d593dc5e04ee 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -210,7 +210,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder::new(subty).subst(tcx, subst)); + vec.push(EarlyBinder::bind(subty).subst(tcx, subst)); } } _ => vec.push(subty), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 190a7765ff11b..12ad8b0842f5e 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -507,7 +507,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -167,6 +169,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +197,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 2fa445506bc4a..30359e47e73be 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -103,11 +103,14 @@ impl RunConfig<'_> { } /// Return a list of crate names selected by `run.paths`. + #[track_caller] pub fn cargo_crates_in_set(&self) -> Interned> { let mut crates = Vec::new(); for krate in &self.paths { let path = krate.assert_single_path(); - let crate_name = self.builder.crate_paths[&path.path]; + let Some(crate_name) = self.builder.crate_paths.get(&path.path) else { + panic!("missing crate for path {}", path.path.display()) + }; crates.push(crate_name.to_string()); } INTERNER.intern_list(crates) @@ -427,25 +430,6 @@ impl<'a> ShouldRun<'a> { } } - /// Indicates it should run if the command-line selects the given crate or - /// any of its (local) dependencies. - /// - /// Compared to `krate`, this treats the dependencies as aliases for the - /// same job. Generally it is preferred to use `krate`, and treat each - /// individual path separately. For example `./x.py test src/liballoc` - /// (which uses `krate`) will test just `liballoc`. However, `./x.py check - /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. - /// `all_krates` should probably be removed at some point. - pub fn all_krates(mut self, name: &str) -> Self { - let mut set = BTreeSet::new(); - for krate in self.builder.in_tree_crates(name, None) { - let path = krate.local_path(self.builder); - set.insert(TaskPath { path, kind: Some(self.kind) }); - } - self.paths.insert(PathSet::Set(set)); - self - } - /// Indicates it should run if the command-line selects the given crate or /// any of its (local) dependencies. /// @@ -458,6 +442,8 @@ impl<'a> ShouldRun<'a> { /// Indicates it should run if the command-line selects any of the given crates. /// /// `make_run` will be called a single time with all matching command-line paths. + /// + /// Prefer [`ShouldRun::crate_or_deps`] to this function where possible. pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self { for krate in crates { let path = krate.local_path(self.builder); @@ -487,7 +473,15 @@ impl<'a> ShouldRun<'a> { self.paths(&[path]) } - // multiple aliases for the same job + /// Multiple aliases for the same job. + /// + /// This differs from [`path`] in that multiple calls to path will end up calling `make_run` + /// multiple times, whereas a single call to `paths` will only ever generate a single call to + /// `paths`. + /// + /// This is analogous to `all_krates`, although `all_krates` is gone now. Prefer [`path`] where possible. + /// + /// [`path`]: ShouldRun::path pub fn paths(mut self, paths: &[&str]) -> Self { static SUBMODULES_PATHS: OnceCell> = OnceCell::new(); @@ -641,12 +635,16 @@ impl Kind { } } - pub fn test_description(&self) -> &'static str { + pub fn description(&self) -> String { match self { Kind::Test => "Testing", Kind::Bench => "Benchmarking", - _ => panic!("not a test command: {}!", self.as_str()), + Kind::Doc => "Documenting", + Kind::Run => "Running", + Kind::Suggest => "Suggesting", + _ => return format!("{self:?}"), } + .to_owned() } } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index edca8fe9b13af..d76b830b0e530 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::config::{Config, DryRun, TargetSelection}; +use crate::doc::DocumentationFormat; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { @@ -66,6 +67,16 @@ macro_rules! std { }; } +macro_rules! doc_std { + ($host:ident => $target:ident, stage = $stage:literal) => { + doc::Std::new( + $stage, + TargetSelection::from_user(stringify!($target)), + DocumentationFormat::HTML, + ) + }; +} + macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( @@ -144,6 +155,9 @@ fn alias_and_path_for_library() { first(cache.all::()), &[std!(A => A, stage = 0), std!(A => A, stage = 1)] ); + + let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"])); + assert_eq!(first(cache.all::()), &[doc_std!(A => A, stage = 0)]); } #[test] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index b11be96cefe62..f5a93854bf2c4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,8 +1,10 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::builder::{crate_description, Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; -use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; +use crate::compile::{ + add_to_sysroot, make_run_crates, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, +}; use crate::config::TargetSelection; use crate::tool::{prepare_tool_cargo, SourceType}; use crate::INTERNER; @@ -12,6 +14,12 @@ use std::path::{Path, PathBuf}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned>, } /// Returns args for the subcommand itself (not for cargo) @@ -66,16 +74,23 @@ fn cargo_subcommand(kind: Kind) -> &'static str { } } +impl Std { + pub fn new(target: TargetSelection) -> Self { + Self { target, crates: INTERNER.intern_list(vec![]) } + } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("sysroot").path("library") + run.crate_or_deps("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Std { target: run.target }); + let crates = make_run_crates(&run, "library"); + run.builder.ensure(Std { target: run.target, crates }); } fn run(self, builder: &Builder<'_>) { @@ -97,7 +112,14 @@ impl Step for Std { cargo.arg("--lib"); } - let _guard = builder.msg_check("library artifacts", target); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + + let _guard = builder.msg_check( + format_args!("library artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -117,7 +139,8 @@ impl Step for Std { } // don't run on std twice with x.py clippy - if builder.kind == Kind::Clippy { + // don't check test dependencies if we haven't built libtest + if builder.kind == Kind::Clippy || !self.crates.is_empty() { return; } @@ -147,8 +170,8 @@ impl Step for Std { // Explicitly pass -p for all dependencies krates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("test", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } let _guard = builder.msg_check("library test/bench/example targets", target); @@ -167,6 +190,22 @@ impl Step for Std { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { pub target: TargetSelection, + /// Whether to build only a subset of crates. + /// + /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. + /// + /// [`compile::Rustc`]: crate::compile::Rustc + crates: Interned>, +} + +impl Rustc { + pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self { + let mut crates = vec![]; + for krate in builder.in_tree_crates("rustc-main", None) { + crates.push(krate.name.to_string()); + } + Self { target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -175,11 +214,12 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("rustc-main").path("compiler") + run.crate_or_deps("rustc-main").path("compiler") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { target: run.target }); + let crates = make_run_crates(&run, "compiler"); + run.builder.ensure(Rustc { target: run.target, crates }); } /// Builds the compiler. @@ -200,7 +240,7 @@ impl Step for Rustc { builder.ensure(crate::compile::Std::new(compiler, compiler.host)); builder.ensure(crate::compile::Std::new(compiler, target)); } else { - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); } let mut cargo = builder.cargo( @@ -218,14 +258,17 @@ impl Step for Rustc { cargo.arg("--all-targets"); } - // Explicitly pass -p for all compiler krates -- this will force cargo + // Explicitly pass -p for all compiler crates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. - for krate in builder.in_tree_crates("rustc-main", Some(target)) { - cargo.arg("-p").arg(krate.name); + for krate in &*self.crates { + cargo.arg("-p").arg(krate); } - let _guard = builder.msg_check("compiler artifacts", target); + let _guard = builder.msg_check( + format_args!("compiler artifacts{}", crate_description(&self.crates)), + target, + ); run_cargo( builder, cargo, @@ -268,7 +311,7 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = builder.cargo( compiler, @@ -318,7 +361,7 @@ impl Step for RustAnalyzer { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Std { target }); + builder.ensure(Std::new(target)); let mut cargo = prepare_tool_cargo( builder, @@ -386,7 +429,7 @@ macro_rules! tool_check_step { let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Rustc { target }); + builder.ensure(Rustc::new(target, builder)); let mut cargo = prepare_tool_cargo( builder, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 33addb90da372..a7ebd018a8791 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,6 +48,17 @@ impl Std { } } +/// Given an `alias` selected by the `Step` and the paths passed on the command line, +/// return a list of the crates that should be built. +/// +/// Normally, people will pass *just* `library` if they pass it. +/// But it's possible (although strange) to pass something like `library std core`. +/// Build all crates anyway, as if they hadn't passed the other args. +pub(crate) fn make_run_crates(run: &RunConfig<'_>, alias: &str) -> Interned> { + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with(alias)); + if has_alias { Default::default() } else { run.cargo_crates_in_set() } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; @@ -62,16 +73,10 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - // Normally, people will pass *just* library if they pass it. - // But it's possible (although strange) to pass something like `library std core`. - // Build all crates anyway, as if they hadn't passed the other args. - let has_library = - run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() }; run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, - crates, + crates: make_run_crates(&run, "library"), }); } @@ -615,6 +620,8 @@ impl Step for Rustc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let mut crates = run.builder.in_tree_crates("rustc-main", None); for (i, krate) in crates.iter().enumerate() { + // We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`. + // Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change. if krate.name == "rustc-main" { crates.swap_remove(i); break; diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b49845386da17..46fc5b80e99d4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -106,11 +106,7 @@ impl Step for JsonDocs { /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - builder.ensure(crate::doc::Std { - stage: builder.top_stage, - target: host, - format: DocumentationFormat::JSON, - }); + builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON)); let dest = "share/doc/rust/json"; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index b52c3b68cc4ff..3de85c91516c4 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -7,7 +7,6 @@ //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. -use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -16,6 +15,7 @@ use crate::builder::crate_description; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; +use crate::compile::make_run_crates; use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::util::{symlink_dir, t, up_to_date}; @@ -87,15 +87,6 @@ book!( StyleGuide, "src/doc/style-guide", "style-guide"; ); -// "library/std" -> ["library", "std"] -// -// Used for deciding whether a particular step is one requested by the user on -// the `x.py doc` command line, which determines whether `--open` will open that -// page. -pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { - path.iter().map(|component| component.to_str().unwrap_or("???")).collect() -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -425,11 +416,18 @@ impl Step for SharedAssets { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Std { pub stage: u32, pub target: TargetSelection, pub format: DocumentationFormat, + crates: Interned>, +} + +impl Std { + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: INTERNER.intern_list(vec![]) } + } } impl Step for Std { @@ -438,7 +436,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("sysroot").path("library").default_condition(builder.config.docs) + run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -450,6 +448,7 @@ impl Step for Std { } else { DocumentationFormat::HTML }, + crates: make_run_crates(&run, "library"), }); } @@ -457,7 +456,7 @@ impl Step for Std { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { + fn run(mut self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; let out = match self.format { @@ -471,41 +470,24 @@ impl Step for Std { builder.ensure(SharedAssets { target: self.target }); } - let index_page = builder.src.join("src/doc/index.md").into_os_string(); + let index_page = builder + .src + .join("src/doc/index.md") + .into_os_string() + .into_string() + .expect("non-utf8 paths are unsupported"); let mut extra_args = match self.format { - DocumentationFormat::HTML => vec![ - OsStr::new("--markdown-css"), - OsStr::new("rust.css"), - OsStr::new("--markdown-no-toc"), - OsStr::new("--index-page"), - &index_page, - ], - DocumentationFormat::JSON => vec![OsStr::new("--output-format"), OsStr::new("json")], + DocumentationFormat::HTML => { + vec!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page] + } + DocumentationFormat::JSON => vec!["--output-format", "json"], }; if !builder.config.docs_minification { - extra_args.push(OsStr::new("--disable-minification")); + extra_args.push("--disable-minification"); } - let requested_crates = builder - .paths - .iter() - .map(components_simplified) - .filter_map(|path| { - if path.len() >= 2 && path.get(0) == Some(&"library") { - // single crate - Some(path[1].to_owned()) - } else if !path.is_empty() { - // ?? - Some(path[0].to_owned()) - } else { - // all library crates - None - } - }) - .collect::>(); - - doc_std(builder, self.format, stage, target, &out, &extra_args, &requested_crates); + doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates); // Don't open if the format is json if let DocumentationFormat::JSON = self.format { @@ -514,7 +496,11 @@ impl Step for Std { // Look for library/std, library/core etc in the `x.py doc` arguments and // open the corresponding rendered docs. - for requested_crate in requested_crates { + if self.crates.is_empty() { + self.crates = INTERNER.intern_list(vec!["library".to_owned()]); + }; + + for requested_crate in &*self.crates { if requested_crate == "library" { // For `x.py doc library --open`, open `std` by default. let index = out.join("std").join("index.html"); @@ -538,7 +524,7 @@ impl Step for Std { /// or remote link. const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"]; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum DocumentationFormat { HTML, JSON, @@ -563,24 +549,22 @@ fn doc_std( stage: u32, target: TargetSelection, out: &Path, - extra_args: &[&OsStr], + extra_args: &[&str], requested_crates: &[String], ) { - builder.info(&format!( - "Documenting{} stage{} library ({}) in {} format", - crate_description(requested_crates), - stage, - target, - format.as_str() - )); if builder.no_std(target) == Some(true) { panic!( "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation." + Set `docs = false` in the config to disable documentation, or pass `--exclude doc::library`." ); } + let compiler = builder.compiler(stage, builder.config.build); + let description = + format!("library{} in {} format", crate_description(&requested_crates), format.as_str()); + let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target); + let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name); @@ -590,35 +574,42 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let run_cargo_rustdoc_for = |package: &str| { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - cargo - .arg("--target-dir") - .arg(&*target_dir.to_string_lossy()) - .arg("-p") - .arg(package) - .arg("-Zskip-rustdoc-fingerprint") - .arg("--") - .arg("-Z") - .arg("unstable-options") - .arg("--resource-suffix") - .arg(&builder.version) - .args(extra_args); - if builder.config.library_docs_private_items { - cargo.arg("--document-private-items").arg("--document-hidden-items"); - } - builder.run(&mut cargo.into()); + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc"); + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + cargo + .arg("--no-deps") + .arg("--target-dir") + .arg(&*target_dir.to_string_lossy()) + .arg("-Zskip-rustdoc-fingerprint") + .rustdocflag("-Z") + .rustdocflag("unstable-options") + .rustdocflag("--resource-suffix") + .rustdocflag(&builder.version); + for arg in extra_args { + cargo.rustdocflag(arg); + } + + if builder.config.library_docs_private_items { + cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items"); + } + + // HACK: because we use `--manifest-path library/sysroot/Cargo.toml`, cargo thinks we only want to document that specific crate, not its dependencies. + // Override its default. + let built_crates = if requested_crates.is_empty() { + builder + .in_tree_crates("sysroot", None) + .into_iter() + .map(|krate| krate.name.to_string()) + .collect() + } else { + requested_crates.to_vec() }; - for krate in STD_PUBLIC_CRATES { - run_cargo_rustdoc_for(krate); - if requested_crates.iter().any(|p| p == krate) { - // No need to document more of the libraries if we have the one we want. - break; - } + for krate in built_crates { + cargo.arg("-p").arg(krate); } + builder.run(&mut cargo.into()); builder.cp_r(&out_dir, &out); } @@ -626,6 +617,28 @@ fn doc_std( pub struct Rustc { pub stage: u32, pub target: TargetSelection, + crates: Interned>, +} + +impl Rustc { + pub(crate) fn new(stage: u32, target: TargetSelection, builder: &Builder<'_>) -> Self { + // Find dependencies for top level crates. + let root_crates = vec![ + INTERNER.intern_str("rustc_driver"), + INTERNER.intern_str("rustc_codegen_llvm"), + INTERNER.intern_str("rustc_codegen_ssa"), + ]; + let crates: Vec<_> = root_crates + .iter() + .flat_map(|krate| { + builder + .in_tree_crates(krate, Some(target)) + .into_iter() + .map(|krate| krate.name.to_string()) + }) + .collect(); + Self { stage, target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -641,7 +654,11 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target }); + run.builder.ensure(Rustc { + stage: run.builder.top_stage, + target: run.target, + crates: make_run_crates(&run, "compiler"), + }); } /// Generates compiler documentation. @@ -654,15 +671,6 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; - let paths = builder - .paths - .iter() - .filter(|path| { - let components = components_simplified(path); - components.len() >= 2 && components[0] == "compiler" - }) - .collect::>(); - // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); @@ -672,7 +680,13 @@ impl Step for Rustc { let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Std::new(compiler, builder.config.build)); - builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + let _guard = builder.msg( + Kind::Doc, + stage, + &format!("compiler{}", crate_description(&self.crates)), + compiler.host, + target, + ); // This uses a shared directory so that librustdoc documentation gets // correctly built and merged with the rustc documentation. This is @@ -710,22 +724,8 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - let root_crates = if paths.is_empty() { - vec![ - INTERNER.intern_str("rustc_driver"), - INTERNER.intern_str("rustc_codegen_llvm"), - INTERNER.intern_str("rustc_codegen_ssa"), - ] - } else { - paths.into_iter().map(|p| builder.crate_paths[p]).collect() - }; - // Find dependencies for top level crates. - let compiler_crates = root_crates.iter().flat_map(|krate| { - builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name) - }); - let mut to_open = None; - for krate in compiler_crates { + for krate in &*self.crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. @@ -785,7 +785,7 @@ macro_rules! tool_doc { if true $(&& $rustc_tool)? { // Build rustc docs so that we generate relative links. - builder.ensure(Rustc { stage, target }); + builder.ensure(Rustc::new(stage, target, builder)); // Rustdoc needs the rustc sysroot available to build. // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index fb76dffd07156..f7d30de67ebab 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1020,8 +1020,8 @@ impl Build { host: impl Into>, target: impl Into>, ) -> Option { - let action = action.into(); - let msg = |fmt| format!("{action:?}ing stage{stage} {what}{fmt}"); + let action = action.into().description(); + let msg = |fmt| format!("{action} stage{stage} {what}{fmt}"); let msg = if let Some(target) = target.into() { let host = host.into().unwrap(); if host == target { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 44cd84be705ab..960abb31b2016 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -101,7 +101,7 @@ impl Step for CrateBootstrap { ); builder.info(&format!( "{} {} stage0 ({})", - builder.kind.test_description(), + builder.kind.description(), path, bootstrap_host, )); @@ -220,7 +220,7 @@ impl Step for HtmlCheck { } // Ensure that a few different kinds of documentation are available. builder.default_doc(&[]); - builder.ensure(crate::doc::Rustc { target: self.target, stage: builder.top_stage }); + builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); } @@ -886,11 +886,11 @@ impl Step for RustdocJSStd { command.arg("--test-file").arg(path); } } - builder.ensure(crate::doc::Std { - target: self.target, - stage: builder.top_stage, - format: DocumentationFormat::HTML, - }); + builder.ensure(crate::doc::Std::new( + builder.top_stage, + self.target, + DocumentationFormat::HTML, + )); builder.run(&mut command); } else { builder.info("No nodejs found, skipping \"tests/rustdoc-js-std\" tests"); diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 806935b827ff5..3ccca1e8b89bc 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.4 \ No newline at end of file +0.16.5 \ No newline at end of file diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 7d3ccb9def360..83887cc44b96b 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -40,7 +40,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let infcx = cx.tcx.infer_ctxt().build(); let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder::new(param_env).subst(infcx.tcx, substs); + let param_env = EarlyBinder::bind(param_env).subst(infcx.tcx, substs); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 423eee47742e0..0ae95b045e03c 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -212,7 +212,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO, crate::int_plus_one::INT_PLUS_ONE_INFO, crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, - crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a418a910ba8ea..a1d2147cb4965 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1219,7 +1219,7 @@ fn needless_borrow_impl_arg_position<'tcx>( return false; } - let predicate = EarlyBinder::new(predicate).subst(cx.tcx, &substs_with_referent_ty); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, &substs_with_referent_ty); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); let infcx = cx.tcx.infer_ctxt().build(); infcx.predicate_must_hold_modulo_regions(&obligation) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index af2aac6ac0d0a..c919b4de65dea 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -243,7 +243,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs | ty::Ref(..) | ty::Slice(_) | ty::Tuple(_) => { - format!("<{}>", EarlyBinder::new(ty).subst(cx.tcx, substs)) + format!("<{}>", EarlyBinder::bind(ty).subst(cx.tcx, substs)) }, _ => ty.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs b/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 6a4861747d267..0000000000000 --- a/src/tools/clippy/clippy_lints/src/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_function_call, paths}; -use rustc_ast::{BorrowKind, LitKind}; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal - /// - /// ### Why is this bad? - /// Creating such a `str` would result in undefined behavior - /// - /// ### Example - /// ```rust - /// # #[allow(unused)] - /// unsafe { - /// std::str::from_utf8_unchecked(b"cl\x82ippy"); - /// } - /// ``` - #[clippy::version = "1.64.0"] - pub INVALID_UTF8_IN_UNCHECKED, - correctness, - "using a non UTF-8 literal in `std::std::from_utf8_unchecked`" -} -declare_lint_pass!(InvalidUtf8InUnchecked => [INVALID_UTF8_IN_UNCHECKED]); - -impl<'tcx> LateLintPass<'tcx> for InvalidUtf8InUnchecked { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some([arg]) = match_function_call(cx, expr, &paths::STR_FROM_UTF8_UNCHECKED) { - match &arg.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => { - if let LitKind::ByteStr(bytes, _) = &lit - && std::str::from_utf8(bytes).is_err() - { - lint(cx, expr.span); - } - }, - ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => { - let elements = args.iter().map(|e|{ - match &e.kind { - ExprKind::Lit(Spanned { node: lit, .. }) => match lit { - LitKind::Byte(b) => Some(*b), - #[allow(clippy::cast_possible_truncation)] - LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::>>(); - - if let Some(elements) = elements - && std::str::from_utf8(&elements).is_err() - { - lint(cx, expr.span); - } - } - _ => {} - } - } - } -} - -fn lint(cx: &LateContext<'_>, span: Span) { - span_lint( - cx, - INVALID_UTF8_IN_UNCHECKED, - span, - "non UTF-8 literal in `std::str::from_utf8_unchecked`", - ); -} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b442a4ac5f611..fcca595c2bc4c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -157,7 +157,6 @@ mod inline_fn_without_body; mod instant_subtraction; mod int_plus_one; mod invalid_upcast_comparisons; -mod invalid_utf8_in_unchecked; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; @@ -937,7 +936,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); - store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index d4cc14bb85632..99f810c27cf82 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { - item_ty == EarlyBinder::new(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) + item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index fdacfa49e92d5..309d2157b76ee 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -428,7 +428,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder::new(predicate).subst(cx.tcx, new_subst); + let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) }) { @@ -438,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder::new(output_ty)) { + new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { expr = parent_expr; ty = new_ty; continue; diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index b0db56bb417ea..7c2a100efdac6 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -43,6 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), + ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), ("clippy::let_underscore_drop", "let_underscore_drop"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 843538e1eb2db..cc3183759ae7a 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let substs = if self.substs.is_empty() { substs } else { - EarlyBinder::new(substs).subst(self.lcx.tcx, self.substs) + EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs) }; let result = self diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs deleted file mode 100644 index 3dc096d3197fb..0000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![warn(clippy::invalid_utf8_in_unchecked)] - -fn main() { - // Valid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"clippy"); - - let x = 0xA0; - std::str::from_utf8_unchecked(&[0xC0, x]); - } - - // Invalid - unsafe { - std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); - std::str::from_utf8_unchecked(b"cl\x82ippy"); - } -} diff --git a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr b/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr deleted file mode 100644 index c89cd2758ee9f..0000000000000 --- a/src/tools/clippy/tests/ui/invalid_utf8_in_unchecked.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:16:9 - | -LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::invalid-utf8-in-unchecked` implied by `-D warnings` - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:17:9 - | -LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'/x82', b'i', b'p', b'p', b'y']); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: non UTF-8 literal in `std::str::from_utf8_unchecked` - --> $DIR/invalid_utf8_in_unchecked.rs:18:9 - | -LL | std::str::from_utf8_unchecked(b"cl/x82ippy"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index dfe45dec8a745..53ac65473b827 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] +#![warn(invalid_from_utf8_unchecked)] #![warn(let_underscore_drop)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index ce8eca5a3081c..722c0b3eb2750 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -38,6 +38,7 @@ #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] +#![allow(invalid_from_utf8_unchecked)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] @@ -87,6 +88,7 @@ #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] +#![warn(clippy::invalid_utf8_in_unchecked)] #![warn(clippy::let_underscore_drop)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 3fca60aa2ebd3..1ff8391766023 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,286 +7,292 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` + --> $DIR/rename.rs:91:9 + | +LL | #![warn(clippy::invalid_utf8_in_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` + error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 48 previous errors +error: aborting due to 49 previous errors diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 0c514fc686420..c5e7f813dd194 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -25,11 +25,11 @@ call-function: ("check-style", { }) call-function: ("check-style", { "theme": "dark", - "background": "rgb(73, 74, 61)", - "border": "rgb(187, 116, 16)", + "background": "#494a3d", + "border": "#bb7410", }) call-function: ("check-style", { "theme": "light", - "background": "rgb(253, 255, 211)", - "border": "rgb(173, 124, 55)", + "background": "#fdffd3", + "border": "#ad7c37", }) diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs new file mode 100644 index 0000000000000..9c8c636812e0d --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -0,0 +1,93 @@ +// check-pass + +#![feature(concat_bytes)] +#![warn(invalid_from_utf8_unchecked)] +#![warn(invalid_from_utf8)] + +pub fn from_utf8_unchecked_mut() { + // Valid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xA0; + std::str::from_utf8_unchecked_mut(&mut [0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked_mut` + } +} + +pub fn from_utf8_unchecked() { + // Valid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8_unchecked(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8_unchecked(b"clippy"); + + let x = 0xA0; + std::str::from_utf8_unchecked(&[0xC0, x]); + } + + // Invalid + unsafe { + std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8_unchecked` + std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8_unchecked` + } +} + +pub fn from_utf8_mut() { + // Valid + { + std::str::from_utf8_mut(&mut [99, 108, 105, 112, 112, 121]); + std::str::from_utf8_mut(&mut [b'c', b'l', b'i', b'p', b'p', b'y']); + + let x = 0xa0; + std::str::from_utf8_mut(&mut [0xc0, x]); + } + + // Invalid + { + std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8_mut` + std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8_mut` + } +} + +pub fn from_utf8() { + // Valid + { + std::str::from_utf8(&[99, 108, 105, 112, 112, 121]); + std::str::from_utf8(&[b'c', b'l', b'i', b'p', b'p', b'y']); + std::str::from_utf8(b"clippy"); + + let x = 0xA0; + std::str::from_utf8(&[0xC0, x]); + } + + // Invalid + { + std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(b"cl\x82ippy"); + //~^ WARN calls to `std::str::from_utf8` + std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + //~^ WARN calls to `std::str::from_utf8` + } +} + +fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr new file mode 100644 index 0000000000000..8e00d3bf872f4 --- /dev/null +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -0,0 +1,110 @@ +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:19:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:4:9 + | +LL | #![warn(invalid_from_utf8_unchecked)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_unchecked_mut` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:21:9 + | +LL | std::str::from_utf8_unchecked_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:39:9 + | +LL | std::str::from_utf8_unchecked(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:41:9 + | +LL | std::str::from_utf8_unchecked(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:43:9 + | +LL | std::str::from_utf8_unchecked(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_unchecked` with a invalid literal are undefined behavior + --> $DIR/invalid_from_utf8.rs:45:9 + | +LL | std::str::from_utf8_unchecked(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:62:9 + | +LL | std::str::from_utf8_mut(&mut [99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + | +note: the lint level is defined here + --> $DIR/invalid_from_utf8.rs:5:9 + | +LL | #![warn(invalid_from_utf8)] + | ^^^^^^^^^^^^^^^^^ + +warning: calls to `std::str::from_utf8_mut` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:64:9 + | +LL | std::str::from_utf8_mut(&mut [b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:82:9 + | +LL | std::str::from_utf8(&[99, 108, 130, 105, 112, 112, 121]); + | ^^^^^^^^^^^^^^^^^^^^-----------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:84:9 + | +LL | std::str::from_utf8(&[b'c', b'l', b'\x82', b'i', b'p', b'p', b'y']); + | ^^^^^^^^^^^^^^^^^^^^----------------------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:86:9 + | +LL | std::str::from_utf8(b"cl\x82ippy"); + | ^^^^^^^^^^^^^^^^^^^^-------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: calls to `std::str::from_utf8` with a invalid literal always return an error + --> $DIR/invalid_from_utf8.rs:88:9 + | +LL | std::str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); + | ^^^^^^^^^^^^^^^^^^^^---------------------------------^ + | | + | the literal was valid UTF-8 up to the 2 bytes + +warning: 12 warnings emitted + diff --git a/tests/ui/process/process-panic-after-fork.rs b/tests/ui/process/process-panic-after-fork.rs index da2683121735f..7c2fc296bb028 100644 --- a/tests/ui/process/process-panic-after-fork.rs +++ b/tests/ui/process/process-panic-after-fork.rs @@ -11,6 +11,8 @@ #![feature(never_type)] #![feature(panic_always_abort)] +#![allow(invalid_from_utf8)] + extern crate libc; use std::alloc::{GlobalAlloc, Layout}; diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs new file mode 100644 index 0000000000000..f679640c5dc90 --- /dev/null +++ b/tests/ui/suggestions/issue-103646.rs @@ -0,0 +1,11 @@ +trait Cat { + fn nya() {} +} + +fn uwu(c: T) { + c.nya(); + //~^ ERROR no method named `nya` found for type parameter `T` in the current scope + //~| Suggestion T::nya() +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-103646.stderr b/tests/ui/suggestions/issue-103646.stderr new file mode 100644 index 0000000000000..3ae9813d4914c --- /dev/null +++ b/tests/ui/suggestions/issue-103646.stderr @@ -0,0 +1,21 @@ +error[E0599]: no method named `nya` found for type parameter `T` in the current scope + --> $DIR/issue-103646.rs:6:7 + | +LL | fn uwu(c: T) { + | - method `nya` not found for this type parameter +LL | c.nya(); + | --^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `T::nya()` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in the trait `Cat` + --> $DIR/issue-103646.rs:2:5 + | +LL | fn nya() {} + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/typeck/issue-106929.rs b/tests/ui/typeck/issue-106929.rs new file mode 100644 index 0000000000000..91342229ae1a5 --- /dev/null +++ b/tests/ui/typeck/issue-106929.rs @@ -0,0 +1,13 @@ +struct Client; + +impl Client { + fn post(&self, _: T, _: T) {} +} + +fn f() { + let c = Client; + post(c, ()); + //~^ ERROR cannot find function `post` in this scope +} + +fn main() {} diff --git a/tests/ui/typeck/issue-106929.stderr b/tests/ui/typeck/issue-106929.stderr new file mode 100644 index 0000000000000..f744e5a41f0cd --- /dev/null +++ b/tests/ui/typeck/issue-106929.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `post` in this scope + --> $DIR/issue-106929.rs:9:5 + | +LL | post(c, ()); + | ^^^^ not found in this scope + | +help: use the `.` operator to call the method `post` on `&Client` + | +LL - post(c, ()); +LL + c.post(()); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`.