diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 56e769ba6b710..ea298d28e72c6 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -75,7 +75,7 @@ //! breaking inconsistently to become //! //! ``` -//! foo(hello, there +//! foo(hello, there, //! good, friends); //! ``` //! @@ -83,7 +83,7 @@ //! //! ``` //! foo(hello, -//! there +//! there, //! good, //! friends); //! ``` diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 069f708856ea4..56d9634213ae5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1317,7 +1317,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { T: TypeFoldable<'tcx>, { if !value.needs_infer() { - return value.clone(); // Avoid duplicated subst-folding. + return value; // Avoid duplicated subst-folding. } let mut r = resolve::OpportunisticVarResolver::new(self); value.fold_with(&mut r) diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 428198cae8917..0fe6564880f01 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -28,27 +28,19 @@ declare_lint_pass!(RedundantSemicolons => [REDUNDANT_SEMICOLONS]); impl EarlyLintPass for RedundantSemicolons { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { - let mut after_item_stmt = false; let mut seq = None; for stmt in block.stmts.iter() { match (&stmt.kind, &mut seq) { (StmtKind::Empty, None) => seq = Some((stmt.span, false)), (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true), - (_, seq) => { - maybe_lint_redundant_semis(cx, seq, after_item_stmt); - after_item_stmt = matches!(stmt.kind, StmtKind::Item(_)); - } + (_, seq) => maybe_lint_redundant_semis(cx, seq), } } - maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt); + maybe_lint_redundant_semis(cx, &mut seq); } } -fn maybe_lint_redundant_semis( - cx: &EarlyContext<'_>, - seq: &mut Option<(Span, bool)>, - after_item_stmt: bool, -) { +fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) { if let Some((span, multiple)) = seq.take() { // FIXME: Find a better way of ignoring the trailing // semicolon from macro expansion @@ -56,12 +48,6 @@ fn maybe_lint_redundant_semis( return; } - // FIXME: Lint on semicolons after item statements - // once doing so doesn't break bootstrapping - if after_item_stmt { - return; - } - cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { let (msg, rem) = if multiple { ("unnecessary trailing semicolons", "remove these semicolons") diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 474e1f8e577f8..c182fa35ee24a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -322,6 +322,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + sym::copy | sym::copy_nonoverlapping => { + let elem_ty = instance.substs.type_at(0); + let elem_layout = self.layout_of(elem_ty)?; + let count = self.read_scalar(args[2])?.to_machine_usize(self)?; + let elem_align = elem_layout.align.abi; + + let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| { + err_ub_format!("overflow computing total size of `{}`", intrinsic_name) + })?; + let src = self.read_scalar(args[0])?.check_init()?; + let src = self.memory.check_ptr_access(src, size, elem_align)?; + let dest = self.read_scalar(args[1])?.check_init()?; + let dest = self.memory.check_ptr_access(dest, size, elem_align)?; + + if let (Some(src), Some(dest)) = (src, dest) { + self.memory.copy( + src, + dest, + size, + intrinsic_name == sym::copy_nonoverlapping, + )?; + } + } sym::offset => { let ptr = self.read_scalar(args[0])?.check_init()?; let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 8d5ed747c3f8f..ea92e23e9bffb 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -90,7 +90,7 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. } ) + matches!(self, TempState::Defined { .. }) } } @@ -309,50 +309,26 @@ impl<'tcx> Validator<'_, 'tcx> { let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - match kind { - BorrowKind::Shared | BorrowKind::Mut { .. } => {} - - // FIXME(eddyb) these aren't promoted here but *could* - // be promoted as part of a larger value because - // `validate_rvalue` doesn't check them, need to - // figure out what is the intended behavior. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), - } - // We can only promote interior borrows of promotable temps (non-temps // don't get promoted anyway). self.validate_local(place.local)?; + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; + + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } - if self.qualif_local::(place.local) { - return Err(Unpromotable); - } - // FIXME(eddyb) this duplicates part of `validate_rvalue`. - let has_mut_interior = - self.qualif_local::(place.local); - if has_mut_interior { + // We cannot promote things that need dropping, since the promoted value + // would not get dropped. + if self.qualif_local::(place.local) { return Err(Unpromotable); } - if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; - - // In theory, any zero-sized value could be borrowed - // mutably without consequences. However, only &mut [] - // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } - } - Ok(()) } _ => bug!(), @@ -572,58 +548,115 @@ impl<'tcx> Validator<'_, 'tcx> { } } - fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { - match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - // ptr-to-int casts are not possible in consts and thus not promotable + fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> { + match kind { + // Reject these borrow types just to be safe. + // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. + BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + + BorrowKind::Shared => { + let has_mut_interior = self.qualif_local::(place.local); + if has_mut_interior { return Err(Unpromotable); } } - Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { - assert!( - op == BinOp::Eq - || op == BinOp::Ne - || op == BinOp::Le - || op == BinOp::Lt - || op == BinOp::Ge - || op == BinOp::Gt - || op == BinOp::Offset - ); + BorrowKind::Mut { .. } => { + let ty = place.ty(self.body, self.tcx).ty; - // raw pointer operations are not allowed inside consts and thus not promotable + // In theory, any zero-sized value could be borrowed + // mutably without consequences. However, only &mut [] + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { + match len.try_eval_usize(self.tcx, self.param_env) { + Some(0) => {} + _ => return Err(Unpromotable), + } + } else { return Err(Unpromotable); } } - - Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable), - - // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous. - _ => {} } + Ok(()) + } + + fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match rvalue { - Rvalue::ThreadLocalRef(_) => Err(Unpromotable), + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => { + self.validate_operand(operand)?; + } - Rvalue::NullaryOp(..) => Ok(()), + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.validate_place(place.as_ref())? + } - Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()), + Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) => self.validate_operand(operand), + Rvalue::Cast(kind, operand, cast_ty) => { + if matches!(kind, CastKind::Misc) { + let operand_ty = operand.ty(self.body, self.tcx); + let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); + let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { + // ptr-to-int casts are not possible in consts and thus not promotable + return Err(Unpromotable); + } + // int-to-ptr casts are fine, they just use the integer value at pointer type. + } + + self.validate_operand(operand)?; + } + + Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + let op = *op; + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { + // raw pointer operations are not allowed inside consts and thus not promotable + assert!(matches!( + op, + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + )); + return Err(Unpromotable); + } + + match op { + // FIXME: reject operations that can fail -- namely, division and modulo. + BinOp::Eq + | BinOp::Ne + | BinOp::Le + | BinOp::Lt + | BinOp::Ge + | BinOp::Gt + | BinOp::Offset + | BinOp::Add + | BinOp::Sub + | BinOp::Mul + | BinOp::Div + | BinOp::Rem + | BinOp::BitXor + | BinOp::BitAnd + | BinOp::BitOr + | BinOp::Shl + | BinOp::Shr => {} + } - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { self.validate_operand(lhs)?; - self.validate_operand(rhs) + self.validate_operand(rhs)?; } + Rvalue::NullaryOp(op, _) => match op { + NullOp::Box => return Err(Unpromotable), + NullOp::SizeOf => {} + }, + Rvalue::AddressOf(_, place) => { // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is // no problem, only using it is. @@ -636,53 +669,36 @@ impl<'tcx> Validator<'_, 'tcx> { }); } } - Err(Unpromotable) + return Err(Unpromotable); } Rvalue::Ref(_, kind, place) => { - if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; - - // In theory, any zero-sized value could be borrowed - // mutably without consequences. However, only &mut [] - // is allowed right now. - if let ty::Array(_, len) = ty.kind() { - match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) => {} - _ => return Err(Unpromotable), - } - } else { - return Err(Unpromotable); - } - } - // Special-case reborrows to be more like a copy of the reference. - let mut place = place.as_ref(); - if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { - let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; + let mut place_simplified = place.as_ref(); + if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection { + let base_ty = + Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind() { - place = PlaceRef { local: place.local, projection: proj_base }; + place_simplified = + PlaceRef { local: place_simplified.local, projection: proj_base }; } } - self.validate_place(place)?; - - let has_mut_interior = self.qualif_local::(place.local); - if has_mut_interior { - return Err(Unpromotable); - } + self.validate_place(place_simplified)?; - Ok(()) + // Check that the reference is fine (using the original place!). + // (Needs to come after `validate_place` to avoid ICEs.) + self.validate_ref(*kind, place)?; } - Rvalue::Aggregate(_, ref operands) => { + Rvalue::Aggregate(_, operands) => { for o in operands { self.validate_operand(o)?; } - - Ok(()) } } + + Ok(()) } fn validate_call( diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index d79dd97a69a75..db2fa5730a338 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -328,8 +328,8 @@ struct SplitIntRange { } impl SplitIntRange { - fn new(r: IntRange) -> Self { - SplitIntRange { range: r.clone(), borders: Vec::new() } + fn new(range: IntRange) -> Self { + SplitIntRange { range, borders: Vec::new() } } /// Internal use diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 4d0c92f51d7ca..efbb0a23a6f01 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -4,24 +4,25 @@ use std::str::FromStr; use rustc_macros::HashStable_Generic; -/// The edition of the compiler (RFC 2052) +/// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).) #[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)] #[derive(HashStable_Generic)] pub enum Edition { - // editions must be kept in order, oldest to newest + // When adding new editions, be sure to do the following: + // + // - update the `ALL_EDITIONS` const + // - update the `EDITION_NAME_LIST` const + // - add a `rust_####()` function to the session + // - update the enum in Cargo's sources as well + // + // Editions *must* be kept in order, oldest to newest. /// The 2015 edition Edition2015, /// The 2018 edition Edition2018, - // when adding new editions, be sure to update: - // - // - Update the `ALL_EDITIONS` const - // - Update the EDITION_NAME_LIST const - // - add a `rust_####()` function to the session - // - update the enum in Cargo's sources as well } -// must be in order from oldest to newest +// Must be in order from oldest to newest. pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018]; pub const EDITION_NAME_LIST: &str = "2015|2018"; diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs index edc6625a6ead7..cea7871923bc6 100644 --- a/compiler/rustc_span/src/lev_distance.rs +++ b/compiler/rustc_span/src/lev_distance.rs @@ -1,10 +1,16 @@ +//! Levenshtein distances. +//! +//! The [Levenshtein distance] is a metric for measuring the difference between two strings. +//! +//! [Levenshtein distance]: https://en.wikipedia.org/wiki/Levenshtein_distance + use crate::symbol::Symbol; use std::cmp; #[cfg(test)] mod tests; -/// Finds the Levenshtein distance between two strings +/// Finds the Levenshtein distance between two strings. pub fn lev_distance(a: &str, b: &str) -> usize { // cases which don't require further computation if a.is_empty() { @@ -35,14 +41,14 @@ pub fn lev_distance(a: &str, b: &str) -> usize { dcol[t_last + 1] } -/// Finds the best match for a given word in the given iterator +/// Finds the best match for a given word in the given iterator. /// /// As a loose rule to avoid the obviously incorrect suggestions, it takes /// an optional limit for the maximum allowable edit distance, which defaults /// to one-third of the given word. /// -/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with -/// a lower(upper)case letters mismatch. +/// Besides Levenshtein, we use case insensitive comparison to improve accuracy +/// on an edge case with a lower(upper)case letters mismatch. #[cold] pub fn find_best_match_for_name( name_vec: &[Symbol], @@ -98,7 +104,7 @@ fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option String { let mut split_words: Vec<&str> = name.split('_').collect(); - // We are sorting primitive &strs and can use unstable sort here + // We are sorting primitive &strs and can use unstable sort here. split_words.sort_unstable(); split_words.join("_") } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index fbef4d06709ec..8009530717566 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1,4 +1,13 @@ -//! The source positions and related helper functions. +//! Source positions and related helper functions. +//! +//! Important concepts in this module include: +//! +//! - the *span*, represented by [`SpanData`] and related types; +//! - source code as represented by a [`SourceMap`]; and +//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module. +//! +//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata, +//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`]. //! //! ## Note //! @@ -124,7 +133,7 @@ pub enum RealFileName { impl RealFileName { /// Returns the path suitable for reading from the file system on the local host. - /// Avoid embedding this in build artifacts; see `stable_name` for that. + /// Avoid embedding this in build artifacts; see `stable_name()` for that. pub fn local_path(&self) -> &Path { match self { RealFileName::Named(p) @@ -133,7 +142,7 @@ impl RealFileName { } /// Returns the path suitable for reading from the file system on the local host. - /// Avoid embedding this in build artifacts; see `stable_name` for that. + /// Avoid embedding this in build artifacts; see `stable_name()` for that. pub fn into_local_path(self) -> PathBuf { match self { RealFileName::Named(p) @@ -143,7 +152,7 @@ impl RealFileName { /// Returns the path suitable for embedding into build artifacts. Note that /// a virtualized path will not correspond to a valid file system path; see - /// `local_path` for something that is more likely to return paths into the + /// `local_path()` for something that is more likely to return paths into the /// local host file system. pub fn stable_name(&self) -> &Path { match self { @@ -173,7 +182,7 @@ pub enum FileName { /// Custom sources for explicit parser calls from plugins and drivers. Custom(String), DocTest(PathBuf, isize), - /// Post-substitution inline assembly from LLVM + /// Post-substitution inline assembly from LLVM. InlineAsm(u64), } @@ -266,14 +275,17 @@ impl FileName { } } +/// Represents a span. +/// /// Spans represent a region of code, used for error reporting. Positions in spans -/// are *absolute* positions from the beginning of the source_map, not positions -/// relative to `SourceFile`s. Methods on the `SourceMap` can be used to relate spans back +/// are *absolute* positions from the beginning of the [`SourceMap`], not positions +/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back /// to the original source. -/// You must be careful if the span crosses more than one file - you will not be +/// +/// You must be careful if the span crosses more than one file, since you will not be /// able to use many of the functions on spans in source_map and you cannot assume -/// that the length of the `span = hi - lo`; there may be space in the `BytePos` -/// range between files. +/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the +/// [`BytePos`] range between files. /// /// `SpanData` is public because `Span` uses a thread-local interner and can't be /// sent to other threads, but some pieces of performance infra run in a separate thread. @@ -384,7 +396,7 @@ impl Span { Span::new(lo, hi, SyntaxContext::root()) } - /// Returns a new span representing an empty span at the beginning of this span + /// Returns a new span representing an empty span at the beginning of this span. #[inline] pub fn shrink_to_lo(self) -> Span { let span = self.data(); @@ -398,7 +410,7 @@ impl Span { } #[inline] - /// Returns true if hi == lo + /// Returns `true` if `hi == lo`. pub fn is_empty(&self) -> bool { let span = self.data(); span.hi == span.lo @@ -512,7 +524,7 @@ impl Span { } /// Checks if a span is "internal" to a macro in which `unsafe` - /// can be used without triggering the `unsafe_code` lint + /// can be used without triggering the `unsafe_code` lint. // (that is, a macro marked with `#[allow_internal_unsafe]`). pub fn allows_unsafe(&self) -> bool { self.ctxt().outer_expn_data().allow_internal_unsafe @@ -700,6 +712,7 @@ impl Span { } } +/// A span together with some additional data. #[derive(Clone, Debug)] pub struct SpanLabel { /// The span we are going to include in the final snippet. @@ -743,7 +756,7 @@ impl Decodable for Span { /// any spans that are debug-printed during the closure's execution. /// /// Normally, the global `TyCtxt` is used to retrieve the `SourceMap` -/// (see `rustc_interface::callbacks::span_debug1). However, some parts +/// (see `rustc_interface::callbacks::span_debug1`). However, some parts /// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before /// a `TyCtxt` is available. In this case, we fall back to /// the `SourceMap` provided to this function. If that is not available, @@ -994,9 +1007,9 @@ pub enum ExternalSource { Unneeded, Foreign { kind: ExternalSourceKind, - /// This SourceFile's byte-offset within the source_map of its original crate + /// This SourceFile's byte-offset within the source_map of its original crate. original_start_pos: BytePos, - /// The end of this SourceFile within the source_map of its original crate + /// The end of this SourceFile within the source_map of its original crate. original_end_pos: BytePos, }, } @@ -1099,7 +1112,7 @@ impl SourceFileHash { } } -/// A single source in the `SourceMap`. +/// A single source in the [`SourceMap`]. #[derive(Clone)] pub struct SourceFile { /// The name of the file that the source came from. Source that doesn't @@ -1580,7 +1593,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec) { /// Replaces `\r\n` with `\n` in-place in `src`. /// -/// Returns error if there's a lone `\r` in the string +/// Returns error if there's a lone `\r` in the string. fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec) { if !src.as_bytes().contains(&b'\r') { return; @@ -1705,13 +1718,16 @@ macro_rules! impl_pos { } impl_pos! { - /// A byte offset. Keep this small (currently 32-bits), as AST contains - /// a lot of them. + /// A byte offset. + /// + /// Keep this small (currently 32-bits), as AST contains a lot of them. #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct BytePos(pub u32); - /// A character offset. Because of multibyte UTF-8 characters, a byte offset - /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// A character offset. + /// + /// Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`] /// values to `CharPos` values as necessary. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct CharPos(pub usize); @@ -1835,8 +1851,9 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { } /// Requirements for a `StableHashingContext` to be used in this crate. -/// This is a hack to allow using the `HashStable_Generic` derive macro -/// instead of implementing everything in librustc_middle. +/// +/// This is a hack to allow using the [`HashStable_Generic`] derive macro +/// instead of implementing everything in rustc_middle. pub trait HashStableContext { fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher); fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher); @@ -1856,6 +1873,7 @@ where /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column) /// triple, which stays the same even if the containing `SourceFile` has moved /// within the `SourceMap`. + /// /// Also note that we are hashing byte offsets for the column, not unicode /// codepoint offsets. For the purpose of the hash that's sufficient. /// Also, hashing filenames is expensive so we avoid doing it twice when the diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index e9b4eb6e4abe0..fefc0cb48ddd8 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1,9 +1,11 @@ -//! The `SourceMap` tracks all the source code used within a single crate, mapping +//! Types for tracking pieces of source code within a crate. +//! +//! The [`SourceMap`] tracks all the source code used within a single crate, mapping //! from integer byte positions to the original source code location. Each bit //! of source parsed during crate parsing (typically files, in-memory strings, //! or various bits of macro expansion) cover a continuous range of bytes in the -//! `SourceMap` and are represented by `SourceFile`s. Byte positions are stored in -//! `Span` and used pervasively in the compiler. They are absolute positions +//! `SourceMap` and are represented by [`SourceFile`]s. Byte positions are stored in +//! [`Span`] and used pervasively in the compiler. They are absolute positions //! within the `SourceMap`, which upon request can be converted to line and column //! information, source code snippets, etc. diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index b05e01d666bd6..ceb9b59b13ad1 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxIndexSet; /// A compressed span. /// -/// `SpanData` is 12 bytes, which is a bit too big to stick everywhere. `Span` +/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span` /// is a form that only takes up 8 bytes, with less space for the length and /// context. The vast majority (99.9%+) of `SpanData` instances will fit within /// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are @@ -42,13 +42,11 @@ use rustc_data_structures::fx::FxIndexSet; /// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base` /// values never cause interning. The number of bits needed for `base` /// depends on the crate size. 32 bits allows up to 4 GiB of code in a crate. -/// `script-servo` is the largest crate in `rustc-perf`, requiring 26 bits -/// for some spans. /// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits /// in `SpanData`, which means that large `len` values will cause interning. /// The number of bits needed for `len` does not depend on the crate size. -/// The most common number of bits for `len` are 0--7, with a peak usually at -/// 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough +/// The most common numbers of bits for `len` are from 0 to 7, with a peak usually +/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough /// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur /// dozens of times in a typical crate. /// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that diff --git a/config.toml.example b/config.toml.example index b1fb8904ca988..9e08ce9b27e0c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -669,3 +669,7 @@ changelog-seen = 2 # Whether to allow failures when building tools #missing-tools = false + +# List of compression formats to use when generating dist tarballs. The list of +# formats is provided to rust-installer, which must support all of them. +#compression-formats = ["gz", "xz"] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5292182269385..87863ab5c68f4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1846,20 +1846,22 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] #[inline] -pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { +pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } - if cfg!(debug_assertions) + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst) && is_nonoverlapping(src, dst, count)) { // Not panicking to keep codegen impact smaller. abort(); - } + }*/ // SAFETY: the safety contract for `copy_nonoverlapping` must be // upheld by the caller. @@ -1928,16 +1930,19 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] #[inline] -pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] fn copy(src: *const T, dst: *mut T, count: usize); } - if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { // Not panicking to keep codegen impact smaller. abort(); - } + }*/ // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { copy(src, dst, count) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5b19bf6b80f38..4a3020d6b99e1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -73,6 +73,7 @@ #![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] +#![feature(const_intrinsic_copy)] #![feature(const_checked_int_methods)] #![feature(const_euclidean_int_methods)] #![feature(const_float_classify)] @@ -93,6 +94,7 @@ #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] +#![feature(const_ptr_read)] #![feature(const_raw_ptr_comparison)] #![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 57e0bb1499bde..b2a4d897eeded 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -575,8 +575,9 @@ impl MaybeUninit { /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn assume_init_read(&self) -> T { + pub const unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 38519f759ae05..663001167865a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -745,8 +745,9 @@ impl *const T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - pub unsafe fn read(self) -> T + pub const unsafe fn read(self) -> T where T: Sized, { @@ -783,8 +784,9 @@ impl *const T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - pub unsafe fn read_unaligned(self) -> T + pub const unsafe fn read_unaligned(self) -> T where T: Sized, { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 27d49529a5ec2..807f114ea466c 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -685,7 +685,8 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn read(src: *const T) -> T { +#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] +pub const unsafe fn read(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. @@ -784,7 +785,8 @@ pub unsafe fn read(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -pub unsafe fn read_unaligned(src: *const T) -> T { +#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] +pub const unsafe fn read_unaligned(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 92f4e431de499..785bf70c2992c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -852,8 +852,9 @@ impl *mut T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - pub unsafe fn read(self) -> T + pub const unsafe fn read(self) -> T where T: Sized, { @@ -890,8 +891,9 @@ impl *mut T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] - pub unsafe fn read_unaligned(self) -> T + pub const unsafe fn read_unaligned(self) -> T where T: Sized, { diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs new file mode 100644 index 0000000000000..4acd059ab03df --- /dev/null +++ b/library/core/tests/const_ptr.rs @@ -0,0 +1,51 @@ +// Aligned to two bytes +const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])]; + +const fn unaligned_ptr() -> *const u16 { + // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 + unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } +} + +#[test] +fn read() { + use core::ptr; + + const FOO: i32 = unsafe { ptr::read(&42 as *const i32) }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn const_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn mut_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16; + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 2828235c3e38d..9e8ec7060216b 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,6 +13,8 @@ #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -34,6 +36,7 @@ #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] @@ -82,6 +85,10 @@ mod cell; mod char; mod clone; mod cmp; + +#[cfg(not(bootstrap))] +mod const_ptr; + mod fmt; mod hash; mod intrinsics; diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 5d0fedd4d9ccc..a09a2e91804b1 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -267,3 +267,10 @@ fn uninit_write_slice_cloned_no_drop() { forget(src); } + +#[test] +#[cfg(not(bootstrap))] +fn uninit_const_assume_init_read() { + const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() }; + assert_eq!(FOO, 42); +} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 97f40815b87b4..b8bae69d06330 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -351,11 +351,13 @@ def output(filepath): with open(tmp, 'w') as f: yield f try: - os.remove(filepath) # PermissionError/OSError on Win32 if in use - os.rename(tmp, filepath) + if os.path.exists(filepath): + os.remove(filepath) # PermissionError/OSError on Win32 if in use except OSError: shutil.copy2(tmp, filepath) os.remove(tmp) + return + os.rename(tmp, filepath) class RustBuild(object): diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index def8f21543626..8a3b936d80d5c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -148,6 +148,7 @@ pub struct Config { pub dist_sign_folder: Option, pub dist_upload_addr: Option, pub dist_gpg_password_file: Option, + pub dist_compression_formats: Option>, // libstd features pub backtrace: bool, // support for RUST_BACKTRACE @@ -438,6 +439,7 @@ struct Dist { upload_addr: Option, src_tarball: Option, missing_tools: Option, + compression_formats: Option>, } #[derive(Deserialize)] @@ -936,6 +938,7 @@ impl Config { config.dist_sign_folder = t.sign_folder.map(PathBuf::from); config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from); config.dist_upload_addr = t.upload_addr; + config.dist_compression_formats = t.compression_formats; set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 42f00ce962174..2cabaee68ea67 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -147,6 +147,8 @@ def v(*args): "experimental LLVM targets to build") v("release-channel", "rust.channel", "the name of the release channel to build") v("release-description", "rust.description", "optional descriptive string for version output") +v("dist-compression-formats", None, + "comma-separated list of compression formats to use") # Used on systems where "cc" is unavailable v("default-linker", "rust.default-linker", "the default linker") @@ -349,6 +351,8 @@ def set(key, value): elif option.name == 'option-checking': # this was handled above pass + elif option.name == 'dist-compression-formats': + set('dist.compression-formats', value.split(',')) else: raise RuntimeError("unhandled option {}".format(option.name)) diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 0255f79b65929..137370fe6cb4f 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -294,11 +294,25 @@ impl<'a> Tarball<'a> { build_cli(&self, &mut cmd); cmd.arg("--work-dir").arg(&self.temp_dir); + if let Some(formats) = &self.builder.config.dist_compression_formats { + assert!(!formats.is_empty(), "dist.compression-formats can't be empty"); + cmd.arg("--compression-formats").arg(formats.join(",")); + } self.builder.run(&mut cmd); if self.delete_temp_dir { t!(std::fs::remove_dir_all(&self.temp_dir)); } - crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)) + // Use either the first compression format defined, or "gz" as the default. + let ext = self + .builder + .config + .dist_compression_formats + .as_ref() + .and_then(|formats| formats.get(0)) + .map(|s| s.as_str()) + .unwrap_or("gz"); + + crate::dist::distdir(self.builder).join(format!("{}.tar.{}", package_name, ext)) } } diff --git a/src/ci/run.sh b/src/ci/run.sh index 181a7fcb73266..1958b6ee41d7f 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -53,6 +53,11 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-units-std=1" +# Only produce xz tarballs on CI. gz tarballs will be generated by the release +# process by recompressing the existing xz ones. This decreases the storage +# space required for CI artifacts. +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz" + if [ "$DIST_SRC" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src" fi diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 874550da8b0c9..030892a432b31 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -4,17 +4,21 @@ {data_ptr,[length]s8} data_ptr,[length]s8 - length - - length - data_ptr - + length + + + + length + data_ptr + + + - {{ length={length} }} + {{ len={length} }} - length + length length data_ptr diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index de30b58526a13..cfaafc5734bce 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -1,9 +1,9 @@ - {{ size={len} }} + {{ len={len} }} - len + len buf.cap len @@ -12,9 +12,9 @@ - {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} + {{ len={tail <= head ? head - tail : buf.cap - tail + head} }} - tail <= head ? head - tail : buf.cap - tail + head + tail <= head ? head - tail : buf.cap - tail + head buf.cap @@ -31,7 +31,7 @@ - {{ size={len} }} + {{ len={len} }} len @@ -42,15 +42,37 @@ - {*(char**)this,[vec.len]s8} - *(char**)this,[vec.len]s8 + {(char*)vec.buf.ptr.pointer,[vec.len]s8} + (char*)vec.buf.ptr.pointer,[vec.len]s8 - vec.len + vec.len vec.buf.cap - - vec.len - *(char**)this - + + + + vec.len + (char*)vec.buf.ptr.pointer + + + + + + + {ptr.pointer->value} + + ptr.pointer->value + + + + {ptr.pointer->data} + + ptr.pointer->data + + + + {ptr.pointer->data} + + ptr.pointer->data diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 0e703b3b95026..984a8bfb13c7c 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -6,34 +6,28 @@ pointer + {{ Shared {pointer} }} pointer + - {{ None }} - {{ Some {__0} }} + None + Some({__0}) - (ULONG)(RUST$ENUM$DISR != 0) - __0 - - (ULONG)(RUST$ENUM$DISR != 0) - &__0 - + __0 + - {{ None }} - {{ Some {($T1 *)this} }} + None + Some({($T1 *)this}) - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - - (ULONG)(*(PVOID *)this != nullptr) - ($T1 *)this - + ($T1 *)this + \ No newline at end of file diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index 9550c25f2fcfe..7e5ee7b13daf1 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -26,9 +26,9 @@ --> - {{ size={base.table.items} }} + {{ len={base.table.items} }} - base.table.items + base.table.items base.table.items + base.table.growth_left base.hash_builder @@ -50,9 +50,9 @@ - {{ size={base.map.table.items} }} + {{ len={base.map.table.items} }} - base.map.table.items + base.map.table.items base.map.table.items + base.map.table.growth_left base.map.hash_builder diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 7313c761eae8c..02dd42ce0c14d 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -558,12 +558,12 @@ crate fn make_test( "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n", inner_attr, inner_fn_name ), - format!("\n}}; {}().unwrap() }}", inner_fn_name), + format!("\n}} {}().unwrap() }}", inner_fn_name), ) } else if test_id.is_some() { ( format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name), - format!("\n}}; {}() }}", inner_fn_name), + format!("\n}} {}() }}", inner_fn_name), ) } else { ("fn main() {\n".into(), "\n}".into()) diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 1aea85e99708a..465b2b1d69b34 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -292,7 +292,7 @@ use std::io; let mut input = String::new(); io::stdin().read_line(&mut input)?; Ok::<(), io:Error>(()) -}; _inner().unwrap() }" +} _inner().unwrap() }" .to_string(); let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); @@ -306,7 +306,7 @@ fn make_test_named_wrapper() { let expected = "#![allow(unused)] fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { assert_eq!(2+2, 4); -}; _doctest_main__some_unique_name() }" +} _doctest_main__some_unique_name() }" .to_string(); let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 2ae28dcd0c478..20cf48915c3c8 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -418,7 +418,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { struct HeadingLinks<'a, 'b, 'ids, I> { inner: I, toc: Option<&'b mut TocBuilder>, - buf: VecDeque<(Event<'a>, Range)>, + buf: VecDeque>, id_map: &'ids mut IdMap, } @@ -428,10 +428,8 @@ impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> { } } -impl<'a, 'b, 'ids, I: Iterator, Range)>> Iterator - for HeadingLinks<'a, 'b, 'ids, I> -{ - type Item = (Event<'a>, Range); +impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, 'b, 'ids, I> { + type Item = Event<'a>; fn next(&mut self) -> Option { if let Some(e) = self.buf.pop_front() { @@ -439,29 +437,31 @@ impl<'a, 'b, 'ids, I: Iterator, Range)>> Iterator } let event = self.inner.next(); - if let Some((Event::Start(Tag::Heading(level)), _)) = event { + if let Some(Event::Start(Tag::Heading(level))) = event { let mut id = String::new(); for event in &mut self.inner { - match &event.0 { + match &event { Event::End(Tag::Heading(..)) => break, - Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); - self.buf.push_back(event); } - _ => self.buf.push_back(event), + _ => {} + } + match event { + Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {} + event => self.buf.push_back(event), } } let id = self.id_map.derive(id); if let Some(ref mut builder) = self.toc { let mut html_header = String::new(); - html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone())); + html::push_html(&mut html_header, self.buf.iter().cloned()); let sec = builder.push(level as u32, html_header, id.clone()); - self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); + self.buf.push_front(Event::Html(format!("{} ", sec).into())); } - self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); + self.buf.push_back(Event::Html(format!("", level).into())); let start_tags = format!( "\ @@ -469,7 +469,7 @@ impl<'a, 'b, 'ids, I: Iterator, Range)>> Iterator id = id, level = level ); - return Some((Event::Html(start_tags.into()), 0..0)); + return Some(Event::Html(start_tags.into())); } event } @@ -560,23 +560,23 @@ impl<'a, I> Footnotes<'a, I> { } } -impl<'a, I: Iterator, Range)>> Iterator for Footnotes<'a, I> { - type Item = (Event<'a>, Range); +impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { + type Item = Event<'a>; fn next(&mut self) -> Option { loop { match self.inner.next() { - Some((Event::FootnoteReference(ref reference), range)) => { + Some(Event::FootnoteReference(ref reference)) => { let entry = self.get_entry(&reference); let reference = format!( "{0}", (*entry).1 ); - return Some((Event::Html(reference.into()), range)); + return Some(Event::Html(reference.into())); } - Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => { + Some(Event::Start(Tag::FootnoteDefinition(def))) => { let mut content = Vec::new(); - for (event, _) in &mut self.inner { + for event in &mut self.inner { if let Event::End(Tag::FootnoteDefinition(..)) = event { break; } @@ -607,7 +607,7 @@ impl<'a, I: Iterator, Range)>> Iterator for Footnotes<' ret.push_str(""); } ret.push_str(""); - return Some((Event::Html(ret.into()), 0..0)); + return Some(Event::Html(ret.into())); } else { return None; } @@ -917,14 +917,13 @@ impl Markdown<'_> { }; let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); - let p = p.into_offset_iter(); let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = Footnotes::new(p); - let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); + let p = LinkReplacer::new(p, links); let p = CodeBlocks::new(p, codes, edition, playground); + let p = Footnotes::new(p); html::push_html(&mut s, p); s @@ -935,7 +934,7 @@ impl MarkdownWithToc<'_> { crate fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, opts()); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -943,8 +942,8 @@ impl MarkdownWithToc<'_> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); + let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); html::push_html(&mut s, p); } @@ -960,19 +959,19 @@ impl MarkdownHtml<'_> { if md.is_empty() { return String::new(); } - let p = Parser::new_ext(md, opts()).into_offset_iter(); + let p = Parser::new_ext(md, opts()); // Treat inline HTML as plain text. - let p = p.map(|event| match event.0 { - Event::Html(text) => (Event::Text(text), event.1), + let p = p.map(|event| match event { + Event::Html(text) => Event::Text(text), _ => event, }); let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); + let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); - let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground); html::push_html(&mut s, p); s @@ -1027,7 +1026,7 @@ fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) fn push(s: &mut String, text_length: &mut usize, text: &str) { s.push_str(text); *text_length += text.len(); - }; + } 'outer: for event in Parser::new_ext(md, summary_opts()) { match &event { @@ -1125,45 +1124,50 @@ crate fn plain_text_summary(md: &str) -> String { s } -crate fn markdown_links(md: &str) -> Vec<(String, Range)> { +crate fn markdown_links(md: &str) -> Vec<(String, Option>)> { if md.is_empty() { return vec![]; } let mut links = vec![]; - // Used to avoid mutable borrow issues in the `push` closure - // Probably it would be more efficient to use a `RefCell` but it doesn't seem worth the churn. let mut shortcut_links = vec![]; - let span_for_link = |link: &str, span: Range| { - // Pulldown includes the `[]` as well as the URL. Only highlight the relevant span. - // NOTE: uses `rfind` in case the title and url are the same: `[Ok][Ok]` - match md[span.clone()].rfind(link) { - Some(start) => { - let start = span.start + start; - start..start + link.len() + { + let locate = |s: &str| unsafe { + let s_start = s.as_ptr(); + let s_end = s_start.add(s.len()); + let md_start = md.as_ptr(); + let md_end = md_start.add(md.len()); + if md_start <= s_start && s_end <= md_end { + let start = s_start.offset_from(md_start) as usize; + let end = s_end.offset_from(md_start) as usize; + Some(start..end) + } else { + None + } + }; + + 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(&mut push)); + + // There's no need to thread an IdMap through to here because + // the IDs generated aren't going to be emitted anywhere. + let mut ids = IdMap::new(); + let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); + + for ev in iter { + if let Event::Start(Tag::Link(_, dest, _)) = ev { + debug!("found link: {}", dest); + links.push(match dest { + CowStr::Borrowed(s) => (s.to_owned(), locate(s)), + s @ (CowStr::Boxed(..) | CowStr::Inlined(..)) => (s.into_string(), None), + }); } - // This can happen for things other than intra-doc links, like `#1` expanded to `https://github.com/rust-lang/rust/issues/1`. - None => span, - } - }; - let mut push = |link: BrokenLink<'_>| { - let span = span_for_link(link.reference, link.span); - shortcut_links.push((link.reference.to_owned(), span)); - None - }; - 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. - let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p.into_offset_iter(), None, &mut ids)); - - for ev in iter { - if let Event::Start(Tag::Link(_, dest, _)) = ev.0 { - debug!("found link: {}", dest); - let span = span_for_link(&dest, ev.1); - links.push((dest.into_string(), span)); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 2d26e3b71cac3..1fd0b3a293190 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -245,7 +245,7 @@ struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, ori_link: &'a str, - link_range: Range, + link_range: Option>, } #[derive(Clone, Debug, Hash)] @@ -982,7 +982,7 @@ impl LinkCollector<'_, '_> { parent_node: Option, krate: CrateNum, ori_link: String, - link_range: Range, + link_range: Option>, ) -> Option { trace!("considering link '{}'", ori_link); @@ -1628,7 +1628,7 @@ fn report_diagnostic( msg: &str, item: &Item, dox: &str, - link_range: &Range, + link_range: &Option>, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1646,26 +1646,31 @@ fn report_diagnostic( cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { let mut diag = lint.build(msg); - let span = super::source_span_for_markdown_range(cx, dox, link_range, attrs); - if let Some(sp) = span { - diag.set_span(sp); - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); - let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - - // Print the line containing the `link_range` and manually mark it with '^'s. - diag.note(&format!( - "the link appears in this line:\n\n{line}\n\ - {indicator: , dox: &str, - link_range: Range, + link_range: Option>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { let tcx = collector.cx.tcx; @@ -1909,7 +1914,7 @@ fn anchor_failure( item: &Item, path_str: &str, dox: &str, - link_range: Range, + link_range: Option>, failure: AnchorFailure, ) { let msg = match failure { @@ -1934,7 +1939,7 @@ fn ambiguity_error( item: &Item, path_str: &str, dox: &str, - link_range: Range, + link_range: Option>, candidates: Vec, ) { let mut msg = format!("`{}` is ", path_str); @@ -1983,12 +1988,13 @@ fn suggest_disambiguator( path_str: &str, dox: &str, sp: Option, - link_range: &Range, + link_range: &Option>, ) { let suggestion = disambiguator.suggestion(); let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); if let Some(sp) = sp { + let link_range = link_range.as_ref().expect("must have a link range if we have a span"); let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { format!("`{}`", suggestion.as_help(path_str)) } else { @@ -2007,7 +2013,7 @@ fn privacy_error( item: &Item, path_str: &str, dox: &str, - link_range: Range, + link_range: Option>, ) { let sym; let item_name = match item.name { diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index 9f59936a92d10..7115aec1041af 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -10,8 +10,8 @@ // cdb-command: g // cdb-command: dx hash_set,d -// cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet] -// cdb-check: [size] : 15 [Type: [...]] +// cdb-check:hash_set,d [...] : { len=15 } [Type: [...]::HashSet] +// cdb-check: [len] : 15 [Type: [...]] // cdb-check: [capacity] : [...] // cdb-check: [[...]] [...] : 0 [Type: u64] // cdb-command: dx hash_set,d @@ -44,8 +44,8 @@ // cdb-check: [[...]] [...] : 14 [Type: u64] // cdb-command: dx hash_map,d -// cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap] -// cdb-check: [size] : 15 [Type: [...]] +// cdb-check:hash_map,d [...] : { len=15 } [Type: [...]::HashMap] +// cdb-check: [len] : 15 [Type: [...]] // cdb-check: [capacity] : [...] // cdb-check: ["0x0"] : 0 [Type: unsigned __int64] // cdb-command: dx hash_map,d diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 6632488171dad..1a99f8412504a 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -74,8 +74,8 @@ // NOTE: While slices have a .natvis entry that works in VS & VS Code, it fails in CDB 10.0.18362.1 // cdb-command: dx vec,d -// cdb-check:vec,d [...] : { size=4 } [Type: [...]::Vec] -// cdb-check: [size] : 4 [Type: [...]] +// cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec] +// cdb-check: [len] : 4 [Type: [...]] // cdb-check: [capacity] : [...] [Type: [...]] // cdb-check: [0] : 4 [Type: unsigned __int64] // cdb-check: [1] : 5 [Type: unsigned __int64] @@ -89,8 +89,10 @@ // cdb-command: dx string // cdb-check:string : "IAMA string!" [Type: [...]::String] // cdb-check: [] [Type: [...]::String] -// cdb-check: [size] : 0xc [Type: [...]] +// cdb-check: [len] : 0xc [Type: [...]] // cdb-check: [capacity] : 0xc [Type: [...]] + +// cdb-command: dx -r2 string // cdb-check: [0] : 73 'I' [Type: char] // cdb-check: [1] : 65 'A' [Type: char] // cdb-check: [2] : 77 'M' [Type: char] @@ -109,11 +111,11 @@ // NOTE: OsString doesn't have a .natvis entry yet. // cdb-command: dx some -// cdb-check:some : { Some 8 } [Type: [...]::Option] +// cdb-check:some : Some(8) [Type: [...]::Option] // cdb-command: dx none -// cdb-check:none : { None } [Type: [...]::Option] +// cdb-check:none : None [Type: [...]::Option] // cdb-command: dx some_string -// cdb-check:some_string : { Some "IAMA optional string!" } [[...]::Option<[...]::String>] +// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>] #![allow(unused_variables)] use std::ffi::OsString; diff --git a/src/test/rustdoc-ui/reference-links.rs b/src/test/rustdoc-ui/reference-links.rs new file mode 100644 index 0000000000000..7c1a79722c993 --- /dev/null +++ b/src/test/rustdoc-ui/reference-links.rs @@ -0,0 +1,7 @@ +// Test that errors point to the reference, not to the title text. +#![deny(broken_intra_doc_links)] +//! Links to [a] [link][a] +//! +//! [a]: std::process::Comman +//~^ ERROR unresolved +//~| ERROR unresolved diff --git a/src/test/rustdoc-ui/reference-links.stderr b/src/test/rustdoc-ui/reference-links.stderr new file mode 100644 index 0000000000000..6ba73fbdb006d --- /dev/null +++ b/src/test/rustdoc-ui/reference-links.stderr @@ -0,0 +1,20 @@ +error: unresolved link to `std::process::Comman` + --> $DIR/reference-links.rs:5:10 + | +LL | //! [a]: std::process::Comman + | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process` + | +note: the lint level is defined here + --> $DIR/reference-links.rs:2:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `std::process::Comman` + --> $DIR/reference-links.rs:5:10 + | +LL | //! [a]: std::process::Comman + | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs new file mode 100644 index 0000000000000..183aa9e51228c --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.rs @@ -0,0 +1,16 @@ +// error-pattern: any use of this value will cause an error + +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] + +fn main() { + use std::ptr; + + const DATA: [u32; 1] = [42]; + + const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; + + const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr new file mode 100644 index 0000000000000..ca65a079947e0 --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.stderr @@ -0,0 +1,54 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 + | + ::: $DIR/out_of_bounds_read.rs:13:5 + | +LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + | ------------------------------------------------------ + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 + | + ::: $DIR/out_of_bounds_read.rs:14:5 + | +LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + | -------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::mut_ptr::::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 + | + ::: $DIR/out_of_bounds_read.rs:15:5 + | +LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; + | -------------------------------------------------------------------- + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs index 4592bc31a3976..8c79630b7fd2c 100644 --- a/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs +++ b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.rs @@ -1,10 +1,6 @@ -// check-pass -// This test should stop compiling -// we decide to enable this lint for item statements. - #![deny(redundant_semicolons)] fn main() { - fn inner() {}; - struct Bar {}; + fn inner() {}; //~ ERROR unnecessary + struct Bar {}; //~ ERROR unnecessary } diff --git a/src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr new file mode 100644 index 0000000000000..451b152cbe5a0 --- /dev/null +++ b/src/test/ui/lint/redundant-semicolon/item-stmt-semi.stderr @@ -0,0 +1,20 @@ +error: unnecessary trailing semicolon + --> $DIR/item-stmt-semi.rs:4:18 + | +LL | fn inner() {}; + | ^ help: remove this semicolon + | +note: the lint level is defined here + --> $DIR/item-stmt-semi.rs:1:9 + | +LL | #![deny(redundant_semicolons)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary trailing semicolon + --> $DIR/item-stmt-semi.rs:5:18 + | +LL | struct Bar {}; + | ^ help: remove this semicolon + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed index 7f4ebf566733a..84981a5259732 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -39,7 +39,7 @@ fn main() { B(i32), C, D, - }; + } let x = E::A(2); { // lint diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs index aee56dd4a5ef4..94c7c3cadacf7 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs @@ -51,7 +51,7 @@ fn main() { B(i32), C, D, - }; + } let x = E::A(2); { // lint diff --git a/src/tools/rust-installer b/src/tools/rust-installer index d66f476b4d5e7..5254dbfd25d52 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit d66f476b4d5e7fdf1ec215c9ac16c923dc292324 +Subproject commit 5254dbfd25d5284728ab624dca1969d61427a0db