diff --git a/Cargo.lock b/Cargo.lock index 9b5a4c24d25ed..d3f777bc663dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,7 +534,7 @@ dependencies = [ "if_chain", "itertools 0.9.0", "lazy_static", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "quine-mc_cluskey", "quote", "regex-syntax", @@ -1853,7 +1853,7 @@ dependencies = [ "log", "memchr", "open", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "regex", "serde", "serde_derive", @@ -2511,6 +2511,17 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "punycode" version = "0.4.1" @@ -4122,7 +4133,7 @@ dependencies = [ "expect-test", "itertools 0.9.0", "minifier", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "rustc-rayon", "serde", "serde_json", diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ec41fd7a3eebe..4cfb188783ba1 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -584,12 +584,12 @@ impl server::Literal for Rustc<'_> { let start = match start { Bound::Included(lo) => lo, - Bound::Excluded(lo) => lo + 1, + Bound::Excluded(lo) => lo.checked_add(1)?, Bound::Unbounded => 0, }; let end = match end { - Bound::Included(hi) => hi + 1, + Bound::Included(hi) => hi.checked_add(1)?, Bound::Excluded(hi) => hi, Bound::Unbounded => length, }; diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 6a9bb8d6c284f..46ef5ff7dd8c5 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; +use rustc_span::Span; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub enum PointerCast { @@ -113,6 +114,9 @@ pub enum Adjust<'tcx> { pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, + /// The `Span` associated with the field access or method call + /// that triggered this overloaded deref. + pub span: Span, } impl<'tcx> OverloadedDeref<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index afbf805975ce7..6d9d23836fc69 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -612,8 +612,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { type Lifted = ty::adjustment::OverloadedDeref<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.region) - .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl }) + tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, + span: self.span, + }) } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 676065007b7ef..11122b195c0c4 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -66,7 +66,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let span = use_spans.args_or_use(); let move_site_vec = self.get_moved_indexes(location, mpi); - debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec); + debug!( + "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", + move_site_vec, use_spans + ); let move_out_indices: Vec<_> = move_site_vec.iter().map(|move_site| move_site.moi).collect(); @@ -229,6 +232,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } + // Deref::deref takes &self, which cannot cause a move + FnSelfUseKind::DerefCoercion { .. } => unreachable!(), } } else { err.span_label( @@ -355,6 +360,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str); } + if let UseSpans::FnSelfUse { + kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty }, + .. + } = use_spans + { + err.note(&format!( + "{} occurs due to deref coercion to `{}`", + desired_action.as_noun(), + deref_target_ty + )); + + err.span_note(deref_target, "deref defined here"); + } + if let Some((_, mut old_err)) = self.move_error_reported.insert(move_out_indices, (used_place, err)) { @@ -945,7 +964,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name: &str, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { debug!( @@ -1146,7 +1165,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { @@ -1274,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - use_span: UseSpans, + use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index eaaf202f3bd13..eccb6168229c2 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -501,7 +501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn later_use_kind( &self, borrow: &BorrowData<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, location: Location, ) -> (LaterUseKind, Span) { match use_spans { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 3cee32834beb7..4256f6e39d5e8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_span::{ hygiene::{DesugaringKind, ForLoopLoc}, symbol::sym, @@ -538,7 +538,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans { +pub(super) enum UseSpans<'tcx> { /// The access is caused by capturing a variable for a closure. ClosureUse { /// This is true if the captured variable was from a generator. @@ -558,7 +558,7 @@ pub(super) enum UseSpans { fn_call_span: Span, /// The definition span of the method being called fn_span: Span, - kind: FnSelfUseKind, + kind: FnSelfUseKind<'tcx>, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -567,22 +567,32 @@ pub(super) enum UseSpans { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind { +pub(super) enum FnSelfUseKind<'tcx> { /// A normal method call of the form `receiver.foo(a, b, c)` Normal { self_arg: Ident, implicit_into_iter: bool }, /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` FnOnceCall, /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`) Operator { self_arg: Ident }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + }, } -impl UseSpans { +impl UseSpans<'_> { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -590,8 +600,11 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -754,7 +767,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, moved_place: PlaceRef<'tcx>, // Could also be an upvar. location: Location, - ) -> UseSpans { + ) -> UseSpans<'tcx> { use self::UseSpans::*; let stmt = match self.body[location.block].statements.get(location.statement_index) { @@ -809,36 +822,64 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let method_did = if let Some(method_did) = + let (method_did, method_substs) = if let Some(info) = crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block) { - method_did + info } else { return normal_ret; }; let tcx = self.infcx.tcx; - let parent = tcx.parent(method_did); let is_fn_once = parent == tcx.lang_items().fn_once_trait(); let is_operator = !from_hir_call && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p)); + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); let fn_call_span = *fn_span; let self_arg = tcx.fn_arg_names(method_did)[0]; + debug!( + "terminator = {:?} from_hir_call={:?}", + self.body[location.block].terminator, from_hir_call + ); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. let kind = if is_fn_once { - FnSelfUseKind::FnOnceCall + Some(FnSelfUseKind::FnOnceCall) } else if is_operator { - FnSelfUseKind::Operator { self_arg } + Some(FnSelfUseKind::Operator { self_arg }) + } else if is_deref { + let deref_target = + tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, self.param_env, deref_target, method_substs) + .transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, self.param_env); + Some(FnSelfUseKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + }) + } else { + None + } } else { + None + }; + + let kind = kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); let implicit_into_iter = matches!( fn_call_span.desugaring_kind(), Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) ); FnSelfUseKind::Normal { self_arg, implicit_into_iter } - }; + }); return FnSelfUse { var_span: stmt.source_info.span, @@ -859,7 +900,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// and its usage of the local assigned at `location`. /// This is done by searching in statements succeeding `location` /// and originating from `maybe_closure_span`. - pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans { + pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { use self::UseSpans::*; debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); @@ -963,7 +1004,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Helper to retrieve span(s) of given borrow from the current MIR /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans { + pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { let span = self.body.source_info(borrow.reserve_location).span; self.borrow_spans(span, borrow.reserve_location) } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index 6cf1cf20b5afd..e256fb55b124b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> { // Everything that isn't from pattern matching. OtherIllegalMove { original_path: Place<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, kind: IllegalMoveOriginKind<'tcx>, }, } @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let (mut err, err_span) = { let (span, use_spans, original_path, kind): ( Span, - Option, + Option>, Place<'tcx>, &IllegalMoveOriginKind<'_>, ) = match error { @@ -291,7 +291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { move_place: Place<'tcx>, deref_target_place: Place<'tcx>, span: Span, - use_spans: Option, + use_spans: Option>, ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index acd9e3dcf3fcd..64ad0627720aa 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -287,6 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { infcx, + param_env, body: promoted_body, mir_def_id: def.did, move_data: &move_data, @@ -320,6 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, + param_env, body, mir_def_id: def.did, move_data: &mdpe.move_data, @@ -473,6 +475,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 589268e39bda9..70c1aed0957f8 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { .note("each usage of a `const` item creates a new temporary") .note("the mutable reference will refer to this temporary, not the original `const` item"); - if let Some(method_did) = method_did { + if let Some((method_did, _substs)) = method_did { lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method"); } diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs index 049b5f01214cf..5b146eeb87c04 100644 --- a/compiler/rustc_mir/src/util/find_self_call.rs +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -1,30 +1,31 @@ use rustc_middle::mir::*; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; /// Checks if the specified `local` is used as the `self` prameter of a method call /// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is /// returned. -pub fn find_self_call( - tcx: TyCtxt<'_>, - body: &Body<'_>, +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, local: Local, block: BasicBlock, -) -> Option { +) -> Option<(DefId, SubstsRef<'tcx>)> { debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = &body[block].terminator { debug!("find_self_call: func={:?}", func); if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = *ty.kind() { + if let ty::FnDef(def_id, substs) = *ty.kind() { if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = tcx.opt_associated_item(def_id) { debug!("find_self_call: args={:?}", args); if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { if self_place.as_local() == Some(local) { - return Some(def_id); + return Some((def_id, substs)); } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 70c7abc265492..13e69474cfb96 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>( }, }; - overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) + overloaded_place( + cx, + hir_expr, + adjustment.target, + Some(call), + vec![expr.to_ref()], + deref.span, + ) } Adjust::Borrow(AutoBorrow::Ref(_, m)) => { ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() } @@ -277,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Index(ref lhs, ref index) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) + overloaded_place( + cx, + expr, + expr_ty, + None, + vec![lhs.to_ref(), index.to_ref()], + expr.span, + ) } else { ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() } } @@ -285,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) + overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -1025,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>( place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, args: Vec>, + span: Span, ) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types @@ -1040,24 +1055,24 @@ fn overloaded_place<'a, 'tcx>( // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. let (region, mutbl) = match *recv_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), - _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), + _ => span_bug!(span, "overloaded_place: receiver is not a reference"), }; let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = method_callee(cx, expr, expr.span, overloaded_callee); + let fun = method_callee(cx, expr, span, overloaded_callee); let ref_expr = Expr { temp_lifetime, ty: ref_ty, - span: expr.span, + span, kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, - fn_span: expr.span, + fn_span: span, }, }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 407663e57577a..94f795b11ea4d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -416,7 +416,9 @@ symbols! { deny, deprecated, deref, + deref_method, deref_mut, + deref_target, derive, diagnostic, direct, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d6e8b304380ca..f1e8330425e25 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -654,6 +654,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs new file mode 100644 index 0000000000000..28710c60175b0 --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -0,0 +1,25 @@ +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "riscv32-unknown-linux-gnu".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_env: "gnu".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), + arch: "riscv32".to_string(), + target_os: "linux".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + unsupported_abis: super::riscv_base::unsupported_abis(), + code_model: Some(CodeModel::Medium), + cpu: "generic-rv32".to_string(), + features: "+m,+a,+f,+d,+c".to_string(), + llvm_abiname: "ilp32d".to_string(), + max_atomic_width: Some(32), + ..super::linux_base::opts() + }, + }) +} diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 02eefe5622384..b9c5123e49a0e 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'a, 'tcx>, span: Span, + overloaded_span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, @@ -98,10 +99,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { body_id: hir::HirId, span: Span, base_ty: Ty<'tcx>, + overloaded_span: Span, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, + overloaded_span, body_id, param_env, state: AutoderefSnapshot { @@ -190,6 +193,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.span } + pub fn overloaded_span(&self) -> Span { + self.overloaded_span + } + pub fn reached_recursion_limit(&self) -> bool { self.state.reached_recursion_limit } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 82e809d014dd0..90a8d9634ae1e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -483,7 +483,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); if let Some(steps) = autoderef.find_map(|(ty, steps)| { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); diff --git a/compiler/rustc_typeck/src/check/autoderef.rs b/compiler/rustc_typeck/src/check/autoderef.rs index 17364897bde13..59c366ad7d776 100644 --- a/compiler/rustc_typeck/src/check/autoderef.rs +++ b/compiler/rustc_typeck/src/check/autoderef.rs @@ -12,7 +12,18 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span) + } + + /// Like `autoderef`, but provides a custom `Span` to use for calls to + /// an overloaded `Deref` operator + pub fn autoderef_overloaded_span( + &'a self, + span: Span, + base_ty: Ty<'tcx>, + overloaded_span: Span, + ) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span) } pub fn try_overloaded_deref( @@ -44,7 +55,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - Some(OverloadedDeref { region, mutbl }) + Some(OverloadedDeref { + region, + mutbl, + span: autoderef.overloaded_span(), + }) } else { None } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index ae338cccf7977..fd2700b85e279 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -137,7 +137,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> Ty<'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let mut autoderef = + self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span); let (_, n) = match autoderef.nth(pick.autoderefs) { Some(n) => n, None => { diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index ebe71b86c9221..8a62031ec887c 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -446,9 +446,10 @@ fn method_autoderef_steps<'tcx>( tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { let ParamEnvAnd { param_env, value: self_ty } = goal; - let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let mut autoderef = + Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index aed2af20e5271..502cb562385e0 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -242,7 +242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let method = self.register_infer_ok_obligations(ok); if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - *deref = OverloadedDeref { region, mutbl }; + *deref = OverloadedDeref { region, mutbl, span: deref.span }; } // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). // This helps avoid accidental drops. diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 590639d983481..03737e1ef1f4d 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] +#![feature(deque_range)] #![feature(inplace_iteration)] #![feature(iter_map_while)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index f7f78046d089b..4e6043541226f 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; use std::mem::size_of; +use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> where @@ -271,8 +272,8 @@ fn test_split_off_past_end() { #[test] #[should_panic] fn test_split_off_mid_char() { - let mut orig = String::from("山"); - let _ = orig.split_off(1); + let mut shan = String::from("山"); + let _broken_mountain = shan.split_off(1); } #[test] @@ -467,6 +468,20 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut s = String::from("abc"); + s.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut s = String::from("abc"); + s.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_replace_range() { let mut s = "Hello, world!".to_owned(); @@ -504,6 +519,20 @@ fn test_replace_range_inclusive_out_of_bounds() { s.replace_range(5..=5, "789"); } +#[test] +#[should_panic] +fn test_replace_range_start_overflow() { + let mut s = String::from("123"); + s.replace_range((Excluded(usize::MAX), Included(0)), ""); +} + +#[test] +#[should_panic] +fn test_replace_range_end_overflow() { + let mut s = String::from("456"); + s.replace_range((Included(0), Included(usize::MAX)), ""); +} + #[test] fn test_replace_range_empty() { let mut s = String::from("12345"); diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 608a3c9bdf762..563dd7ab6457d 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -3,6 +3,7 @@ use std::collections::TryReserveError::*; use std::fmt::Debug; use std::iter::InPlaceIterable; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::rc::Rc; use std::vec::{Drain, IntoIter}; @@ -645,6 +646,16 @@ fn test_drain_max_vec_size() { assert_eq!(v.len(), usize::MAX - 1); } +#[test] +#[should_panic] +fn test_drain_index_overflow() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + v.drain(0..=usize::MAX); +} + #[test] #[should_panic] fn test_drain_inclusive_out_of_bounds() { @@ -652,6 +663,20 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5..=5); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_drain_leak() { static mut DROPS: i32 = 0; diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 762dc4be44d62..46d8a3c4cb493 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,6 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::hash; @@ -115,6 +116,20 @@ fn test_index_out_of_bounds() { deq[3]; } +#[test] +#[should_panic] +fn test_range_start_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Included(0), Included(usize::MAX))); +} + +#[test] +#[should_panic] +fn test_range_end_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Excluded(usize::MAX), Included(0))); +} + #[derive(Clone, PartialEq, Debug)] enum Taggy { One(i32), diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3953c73319fe4..dde442aa7b52d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -356,8 +356,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn reverse(self) -> Ordering { + pub const fn reverse(self) -> Ordering { match self { Less => Greater, Equal => Equal, @@ -394,8 +395,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "ordering_chaining", since = "1.17.0")] - pub fn then(self, other: Ordering) -> Ordering { + pub const fn then(self, other: Ordering) -> Ordering { match self { Equal => other, _ => self, diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d6c097eee17bf..245152e5490d8 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -63,11 +63,13 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_target"] type Target: ?Sized; /// Dereferences the value. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_method"] fn deref(&self) -> &Self::Target; } diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 4086917780fa4..835289daf715a 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -1,4 +1,7 @@ -use core::cmp::{self, Ordering::*}; +use core::cmp::{ + self, + Ordering::{self, *}, +}; #[test] fn test_int_totalord() { @@ -116,3 +119,16 @@ fn test_user_defined_eq() { assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); } + +#[test] +fn ordering_const() { + // test that the methods of `Ordering` are usable in a const context + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + assert_eq!(REVERSE, Less); + + const THEN: Ordering = Equal.then(ORDERING); + assert_eq!(THEN, Greater); +} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d1960a049d906..00e2dbc9c1dbf 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -95,6 +95,7 @@ //! [`Read`]: io::Read #![stable(feature = "process", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests; @@ -321,7 +322,8 @@ impl Read for ChildStdout { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -381,7 +383,8 @@ impl Read for ChildStderr { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } diff --git a/library/std/src/sys/sgx/fs.rs b/library/std/src/sys/sgx/fs.rs deleted file mode 100644 index ecb5b51cccdcd..0000000000000 --- a/library/std/src/sys/sgx/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/sgx/io.rs b/library/std/src/sys/sgx/io.rs deleted file mode 100644 index d5f475b4310fd..0000000000000 --- a/library/std/src/sys/sgx/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - self.0 = &self.0[n..] - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } -} - -pub struct IoSliceMut<'a>(&'a mut [u8]); - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - let slice = mem::replace(&mut self.0, &mut []); - let (_, remaining) = slice.split_at_mut(n); - self.0 = remaining; - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.0 - } -} diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 1d32eb2542434..1abd91e75e8c4 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -17,14 +17,18 @@ pub mod condvar; pub mod env; pub mod ext; pub mod fd; +#[path = "../unsupported/fs.rs"] pub mod fs; +#[path = "../unsupported/io.rs"] pub mod io; pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; diff --git a/library/std/src/sys/sgx/pipe.rs b/library/std/src/sys/sgx/pipe.rs deleted file mode 100644 index 10d0925823eb9..0000000000000 --- a/library/std/src/sys/sgx/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/sgx/process.rs b/library/std/src/sys/sgx/process.rs deleted file mode 100644 index 4702e5c549228..0000000000000 --- a/library/std/src/sys/sgx/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 8e193935460eb..964abe8b8c9ea 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -52,46 +52,48 @@ unsafe impl GlobalAlloc for System { } } -#[cfg(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - // On android we currently target API level 9 which unfortunately - // doesn't have the `posix_memalign` API used below. Instead we use - // `memalign`, but this unfortunately has the property on some systems - // where the memory returned cannot be deallocated by `free`! - // - // Upon closer inspection, however, this appears to work just fine with - // Android, so for this platform we should be fine to call `memalign` - // (which is present in API level 9). Some helpful references could - // possibly be chromium using memalign [1], attempts at documenting that - // memalign + free is ok [2] [3], or the current source of chromium - // which still uses memalign on android [4]. - // - // [1]: https://codereview.chromium.org/10796020/ - // [2]: https://code.google.com/p/android/issues/detail?id=35391 - // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 - // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ - // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut u8 -} - -#[cfg(not(any( - target_os = "android", - target_os = "illumos", - target_os = "redox", - target_os = "solaris" -)))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. - // Since these are all powers of 2, we can just use max. - let align = layout.align().max(crate::mem::size_of::()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + target_os = "illumos", + target_os = "redox", + target_os = "solaris" + ))] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(layout.align(), layout.size()) as *mut u8 + } + } else if #[cfg(target_os = "wasi")] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 + } + } else { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. + // Since these are all powers of 2, we can just use max. + let align = layout.align().max(crate::mem::size_of::()); + let ret = libc::posix_memalign(&mut out, align, layout.size()); + if ret != 0 { ptr::null_mut() } else { out as *mut u8 } + } + } } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index ecb5b51cccdcd..faa53b6a74422 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -233,10 +233,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { match self.0 {} } - - pub fn diverge(&self) -> ! { - match self.0 {} - } } impl DirBuilder { diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 87f655eecd54e..8ba870c5dbc14 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -8,6 +8,7 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/path.rs"] pub mod path; pub mod pipe; pub mod process; diff --git a/library/std/src/sys/unsupported/path.rs b/library/std/src/sys/unsupported/path.rs deleted file mode 100644 index 840a7ae042625..0000000000000 --- a/library/std/src/sys/unsupported/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 4702e5c549228..7156c9ab92f2b 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -65,8 +65,8 @@ impl From for Stdio { } impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() + fn from(_file: File) -> Stdio { + panic!("unsupported") } } diff --git a/library/std/src/sys/wasi/alloc.rs b/library/std/src/sys/wasi/alloc.rs deleted file mode 100644 index 4d0afe27bb8b2..0000000000000 --- a/library/std/src/sys/wasi/alloc.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -// SAFETY: All methods implemented follow the contract rules defined -// in `GlobalAlloc`. -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - // SAFETY: `libc::malloc` is guaranteed to be safe, it will allocate - // `layout.size()` bytes of memory and return a pointer to it - unsafe { libc::malloc(layout.size()) as *mut u8 } - } else { - // SAFETY: `libc::aligned_alloc` is guaranteed to be safe if - // `layout.size()` is a multiple of `layout.align()`. This - // constraint can be satisfied if `pad_to_align` is called, - // which creates a layout by rounding the size of this layout up - // to a multiple of the layout's alignment - let aligned_layout = layout.pad_to_align(); - unsafe { libc::aligned_alloc(aligned_layout.align(), aligned_layout.size()) as *mut u8 } - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - // SAFETY: `libc::calloc` is safe as long that `layout.size() * 1` - // would not result in integer overflow which cannot happen, - // multiplying by one never overflows - unsafe { libc::calloc(layout.size(), 1) as *mut u8 } - } else { - // SAFETY: The safety contract for `alloc` must be upheld by the caller - let ptr = unsafe { self.alloc(layout.clone()) }; - if !ptr.is_null() { - // SAFETY: in the case of the `ptr` being not null - // it will be properly aligned and a valid ptr - // which satisfies `ptr::write_bytes` safety constrains - unsafe { ptr::write_bytes(ptr, 0, layout.size()) }; - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - // SAFETY: `libc::free` is guaranteed to be safe if `ptr` is allocated - // by this allocator or if `ptr` is NULL - unsafe { libc::free(ptr as *mut libc::c_void) } - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - // SAFETY: `libc::realloc` is safe if `ptr` is allocated by this - // allocator or NULL - // - If `new_size` is 0 and `ptr` is not NULL, it will act as `libc::free` - // - If `new_size` is not 0 and `ptr` is NULL, it will act as `libc::malloc` - // - Else, it will resize the block accordingly - unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } - } else { - // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller - unsafe { realloc_fallback(self, ptr, layout, new_size) } - } - } -} diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 2704ff484f991..a7a4407ac38e2 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -17,6 +17,7 @@ use crate::io as std_io; use crate::mem; +#[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; #[path = "../unsupported/cmath.rs"] @@ -33,8 +34,11 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; #[path = "../unsupported/rwlock.rs"] pub mod rwlock; diff --git a/library/std/src/sys/wasi/path.rs b/library/std/src/sys/wasi/path.rs deleted file mode 100644 index 840a7ae042625..0000000000000 --- a/library/std/src/sys/wasi/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/wasi/pipe.rs b/library/std/src/sys/wasi/pipe.rs deleted file mode 100644 index 180fc114d86db..0000000000000 --- a/library/std/src/sys/wasi/pipe.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/wasi/process.rs b/library/std/src/sys/wasi/process.rs deleted file mode 100644 index c69d6376b0138..0000000000000 --- a/library/std/src/sys/wasi/process.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_file: File) -> Stdio { - panic!("unsupported") - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 3de5890404357..2934ea59ab5ff 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -27,7 +27,7 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/path.rs"] +#[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 794eeafbbbff9..da27d2fbf99a3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -195,6 +195,7 @@ target | std | host | notes `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | +`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 90d2a18ea5819..a40a44fe27da3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.8", default-features = false } minifier = "0.0.33" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a8c60e4a76df4..6c0f1c02ac6da 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,7 +27,6 @@ use rustc_session::lint; use rustc_span::edition::Edition; use rustc_span::Span; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::VecDeque; use std::default::Default; use std::fmt::Write; @@ -39,7 +38,7 @@ use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; -use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; #[cfg(test)] mod tests; @@ -931,15 +930,17 @@ impl Markdown<'_> { if md.is_empty() { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(link) = links.iter().find(|link| &*link.original_text == s) { - Some((link.href.clone(), link.new_text.clone())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -1009,9 +1010,11 @@ impl MarkdownSummaryLine<'_> { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(link) = links.iter().find(|link| &*link.original_text == s) { - Some((link.href.clone(), link.new_text.clone())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } @@ -1020,7 +1023,7 @@ impl MarkdownSummaryLine<'_> { let p = Parser::new_with_broken_link_callback( md, Options::ENABLE_STRIKETHROUGH, - Some(&replacer), + Some(&mut replacer), ); let mut s = String::new(); @@ -1067,7 +1070,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } let mut links = vec![]; - let shortcut_links = RefCell::new(vec![]); + let mut shortcut_links = vec![]; { let locate = |s: &str| unsafe { @@ -1084,11 +1087,13 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } }; - let push = |_: &str, s: &str| { - shortcut_links.borrow_mut().push((s.to_owned(), locate(s))); + let mut push = |link: BrokenLink<'_>| { + // FIXME: use `link.span` instead of `locate` + // (doing it now includes the `[]` as well as the text) + shortcut_links.push((link.reference.to_owned(), locate(link.reference))); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -1106,8 +1111,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } } - let mut shortcut_links = shortcut_links.into_inner(); - links.extend(shortcut_links.drain(..)); + links.append(&mut shortcut_links); links } diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs new file mode 100644 index 0000000000000..e5f3ae45c07d3 --- /dev/null +++ b/src/test/codegen/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,78 @@ +// min-llvm-version: 11.0.0 +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-link-double-anchor.rs new file mode 100644 index 0000000000000..a01211c4f32b1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.rs @@ -0,0 +1,7 @@ +// check-pass + +// regression test for #73264 +// should only give one error +/// docs [label][with#anchor#error] +//~^ WARNING multiple anchors +pub struct S; diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr new file mode 100644 index 0000000000000..3282ec8b79379 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.stderr @@ -0,0 +1,10 @@ +warning: `with#anchor#error` contains multiple anchors + --> $DIR/intra-link-double-anchor.rs:5:18 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^^^^^^^ contains invalid anchor + | + = note: `#[warn(broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index 1770d71e2e2fe..fb884e3129999 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -149,7 +149,7 @@ error: function cannot return without recursing LL | fn deref(&self) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | self.as_ref() - | ---- recursive call site + | ------------- recursive call site | = help: a `loop` may express intention better if this is on purpose diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs new file mode 100644 index 0000000000000..41154388f56a8 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct NotCopy { + inner: bool +} + +impl NotCopy { + fn inner_method(&self) {} +} + +struct Foo { + first: NotCopy, + second: NotCopy +} + +impl Deref for Foo { + type Target = NotCopy; + fn deref(&self) -> &NotCopy { + &self.second + } +} + +fn use_field(val: Foo) { + let _val = val.first; + val.inner; //~ ERROR borrow of +} + +fn use_method(val: Foo) { + let _val = val.first; + val.inner_method(); //~ ERROR borrow of +} + +fn main() {} diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr new file mode 100644 index 0000000000000..e3bdf6d783207 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -0,0 +1,35 @@ +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:25:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner; + | ^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:30:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner_method(); + | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 0081841fec090..37032e73f1900 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:14:18 + --> $DIR/no-capture-arc.rs:14:16 | LL | let arc_v = Arc::new(v); | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index bb4e0871224a2..6f37d4c9d8691 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:12:18 + --> $DIR/no-reuse-move-arc.rs:12:16 | LL | let arc_v = Arc::new(v); | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/tools/cargo b/src/tools/cargo index 875e0123259b0..8777a6b1e8834 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 875e0123259b0b6299903fe4aea0a12ecde9324f +Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110