diff --git a/src/doc/book b/src/doc/book index c8841f2841a2d..f5db319e0b19c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit c8841f2841a2d26124319ddadd1b6a245f9a1856 +Subproject commit f5db319e0b19c22964398d56bc63103d669e1bba diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 37f9e68484111..8204c1d123472 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 37f9e6848411188a1062ead1bd8ebe4b8aa16899 +Subproject commit 8204c1d123472cd17f0c1c5c77300ae802eb0271 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index d22a9c487c780..668fb07b6160b 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit d22a9c487c78095afc4584f1d9b4ec43529d713c +Subproject commit 668fb07b6160b9c468f598e839c1e044db65de30 diff --git a/src/doc/reference b/src/doc/reference index 89dd146154474..3ce94caed4cf9 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 89dd146154474559536d5d4049a03831c501deea +Subproject commit 3ce94caed4cf967106c51ae86be5e098f7875f11 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index a6638463efc76..c106d1683c3a2 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit a6638463efc7631bc0e8dc67ccd256d4e1b61f1a +Subproject commit c106d1683c3a2b0960f0f0fb01728cbb19807332 diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index 4bc0c3a079d5c..e163a166b498f 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -42,10 +42,9 @@ macro_rules! vec { ($elem:expr; $n:expr) => ( $crate::vec::from_elem($elem, $n) ); - ($($x:expr),*) => ( - <[_]>::into_vec(box [$($x),*]) + ($($x:expr),+ $(,)?) => ( + <[_]>::into_vec(box [$($x),+]) ); - ($($x:expr,)*) => ($crate::vec![$($x),*]) } // HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 4ae7532d992b9..4171185c9701a 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -254,7 +254,7 @@ impl [T] { /// Sorts the slice with a key extraction function. /// - /// This sort is stable (i.e., does not reorder equal elements) and `O(m n log(m n))` + /// This sort is stable (i.e., does not reorder equal elements) and `O(m n log n)` /// worst-case, where the key function is `O(m)`. /// /// For expensive key functions (e.g. functions that are not simple property accesses or diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 52e224d2a026f..729e0b897c098 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -706,6 +706,34 @@ impl *const T { } } +#[cfg(not(bootstrap))] +#[lang = "const_slice_ptr"] +impl *const [T] { + /// Returns the length of a raw slice. + /// + /// The returned value is the number of **elements**, not the number of bytes. + /// + /// This function is safe, even when the raw slice cannot be cast to a slice + /// reference because the pointer is null or unaligned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_len)] + /// + /// use std::ptr; + /// + /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); + /// assert_eq!(slice.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn len(self) -> usize { + unsafe { Repr { rust: self }.raw }.len + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 9f85d781d698a..3b7e83bf37fa6 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -894,6 +894,34 @@ impl *mut T { } } +#[cfg(not(bootstrap))] +#[lang = "mut_slice_ptr"] +impl *mut [T] { + /// Returns the length of a raw slice. + /// + /// The returned value is the number of **elements**, not the number of bytes. + /// + /// This function is safe, even when the raw slice cannot be cast to a slice + /// reference because the pointer is null or unaligned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_len)] + /// + /// use std::ptr; + /// + /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); + /// assert_eq!(slice.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn len(self) -> usize { + unsafe { Repr { rust_mut: self }.raw }.len + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *mut T { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 66aad3246183f..4d333fbf8ed97 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1697,7 +1697,7 @@ impl [T] { /// elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place - /// (i.e., does not allocate), and `O(m n log(m n))` worst-case, where the key function is + /// (i.e., does not allocate), and `O(m n log n)` worst-case, where the key function is /// `O(m)`. /// /// # Current implementation diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 51208906c2f2d..7473c890c5ab9 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -507,9 +507,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expanded_fragments.push(Vec::new()); } expanded_fragments[depth - 1].push((expn_id, expanded_fragment)); - if !self.cx.ecfg.single_step { - invocations.extend(new_invocations.into_iter().rev()); - } + invocations.extend(new_invocations.into_iter().rev()); } self.cx.current_expansion = orig_expansion_data; @@ -1819,7 +1817,6 @@ pub struct ExpansionConfig<'feat> { pub recursion_limit: usize, pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes - pub single_step: bool, pub keep_macs: bool, } @@ -1831,7 +1828,6 @@ impl<'feat> ExpansionConfig<'feat> { recursion_limit: 1024, trace_mac: false, should_test: false, - single_step: false, keep_macs: false, } } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 5a3a9cabeb450..53f72804a848d 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -135,6 +135,8 @@ language_item_table! { SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Target::Impl; ConstPtrImplItem, "const_ptr", const_ptr_impl, Target::Impl; MutPtrImplItem, "mut_ptr", mut_ptr_impl, Target::Impl; + ConstSlicePtrImplItem, "const_slice_ptr", const_slice_ptr_impl, Target::Impl; + MutSlicePtrImplItem, "mut_slice_ptr", mut_slice_ptr_impl, Target::Impl; I8ImplItem, "i8", i8_impl, Target::Impl; I16ImplItem, "i16", i16_impl, Target::Impl; I32ImplItem, "i32", i32_impl, Target::Impl; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index aa7c87e9f7bd2..3e1e9cc70aa11 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -384,7 +384,7 @@ trait UnusedDelimLint { fn is_expr_delims_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool { followed_by_block && match inner.kind { - ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true, + ExprKind::Ret(_) | ExprKind::Break(..) => true, _ => parser::contains_exterior_struct_lit(&inner), } } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 3f9aa9ed02d2a..a1ab9a1c342c1 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -353,15 +353,30 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter { static_def_id: Option, is_write: bool, ) -> InterpResult<'tcx> { - if is_write && allocation.mutability == Mutability::Not { - Err(err_ub!(WriteToReadOnly(alloc_id)).into()) - } else if is_write { - Err(ConstEvalErrKind::ModifiedGlobal.into()) - } else if memory_extra.can_access_statics || static_def_id.is_none() { - // `static_def_id.is_none()` indicates this is not a static, but a const or so. - Ok(()) + if is_write { + // Write access. These are never allowed, but we give a targeted error message. + if allocation.mutability == Mutability::Not { + Err(err_ub!(WriteToReadOnly(alloc_id)).into()) + } else { + Err(ConstEvalErrKind::ModifiedGlobal.into()) + } } else { - Err(ConstEvalErrKind::ConstAccessesStatic.into()) + // Read access. These are usually allowed, with some exceptions. + if memory_extra.can_access_statics { + // Machine configuration allows us read from anything (e.g., `static` initializer). + Ok(()) + } else if static_def_id.is_some() { + // Machine configuration does not allow us to read statics + // (e.g., `const` initializer). + Err(ConstEvalErrKind::ConstAccessesStatic.into()) + } else { + // Immutable global, this read is fine. + // But make sure we never accept a read from something mutable, that would be + // unsound. The reason is that as the content of this allocation may be different + // now and at run-time, so if we permit reading now we might return the wrong value. + assert_eq!(allocation.mutability, Mutability::Not); + Ok(()) + } } } } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index cbff99f8da612..4e3c5fa63de2c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1846,11 +1846,9 @@ impl<'a> Parser<'a> { } fn is_try_block(&self) -> bool { - self.token.is_keyword(kw::Try) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && - self.token.uninterpolated_span().rust_2018() && - // Prevent `while try {} {}`, `if try {} {} else {}`, etc. - !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) + self.token.is_keyword(kw::Try) + && self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) + && self.token.uninterpolated_span().rust_2018() } /// Parses an `async move? {...}` expression. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b5d3f7b55029f..9b1c8b9a9c83e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -649,11 +649,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl }) => { - let lang_def_id = match mutbl { - hir::Mutability::Not => lang_items.const_ptr_impl(), - hir::Mutability::Mut => lang_items.mut_ptr_impl(), + let (lang_def_id1, lang_def_id2) = match mutbl { + hir::Mutability::Not => { + (lang_items.const_ptr_impl(), lang_items.const_slice_ptr_impl()) + } + hir::Mutability::Mut => { + (lang_items.mut_ptr_impl(), lang_items.mut_slice_ptr_impl()) + } }; - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(lang_def_id1); + self.assemble_inherent_impl_for_primitive(lang_def_id2); } ty::Int(i) => { let lang_def_id = match i { diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 9ace9f424b74d..2e84173477074 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -112,6 +112,30 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { item.span, ); } + ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) + if matches!(inner.kind, ty::Slice(_)) => + { + self.check_primitive_impl( + def_id, + lang_items.const_slice_ptr_impl(), + None, + "const_slice_ptr", + "*const [T]", + item.span, + ); + } + ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) + if matches!(inner.kind, ty::Slice(_)) => + { + self.check_primitive_impl( + def_id, + lang_items.mut_slice_ptr_impl(), + None, + "mut_slice_ptr", + "*mut [T]", + item.span, + ); + } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => { self.check_primitive_impl( def_id, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index da0e97f1075b0..c80967a4b33f2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -62,6 +62,8 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { lang_items.slice_u8_alloc_impl(), lang_items.const_ptr_impl(), lang_items.mut_ptr_impl(), + lang_items.const_slice_ptr_impl(), + lang_items.mut_slice_ptr_impl(), ]; for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 7841d5eef58a8..fbbe172afb81f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -263,7 +263,12 @@ fn run_test( if no_run && !compile_fail { compiler.arg("--emit=metadata"); } - compiler.arg("--target").arg(target.to_string()); + compiler.arg("--target").arg(match target { + TargetTriple::TargetTriple(s) => s, + TargetTriple::TargetPath(path) => { + path.to_str().expect("target path must be valid unicode").to_string() + } + }); compiler.arg("-"); compiler.stdin(Stdio::piped()); @@ -312,8 +317,8 @@ fn run_test( if let Some(tool) = runtool { cmd = Command::new(tool); - cmd.arg(output_file); cmd.args(runtool_args); + cmd.arg(output_file); } else { cmd = Command::new(output_file); } diff --git a/src/test/ui/try-block/try-block-in-match.rs b/src/test/ui/try-block/try-block-in-match.rs index bce0d0340b658..cd0b967e79d07 100644 --- a/src/test/ui/try-block/try-block-in-match.rs +++ b/src/test/ui/try-block/try-block-in-match.rs @@ -1,7 +1,11 @@ +// run-pass // compile-flags: --edition 2018 #![feature(try_blocks)] fn main() { - match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try` + match try { } { + Err(()) => (), + Ok(()) => (), + } } diff --git a/src/test/ui/try-block/try-block-in-match.stderr b/src/test/ui/try-block/try-block-in-match.stderr deleted file mode 100644 index 936e0fe19bafe..0000000000000 --- a/src/test/ui/try-block/try-block-in-match.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: expected expression, found reserved keyword `try` - --> $DIR/try-block-in-match.rs:6:11 - | -LL | match try { false } { _ => {} } - | ----- ^^^ expected expression - | | - | while parsing this match expression - -error: aborting due to previous error - diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs index 98af796dd3780..33d2723651929 100644 --- a/src/test/ui/try-block/try-block-in-while.rs +++ b/src/test/ui/try-block/try-block-in-while.rs @@ -3,5 +3,6 @@ #![feature(try_blocks)] fn main() { - while try { false } {} //~ ERROR expected expression, found reserved keyword `try` + while try { false } {} + //~^ ERROR the trait bound `bool: std::ops::Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index 026df15eb877a..ac41ddfd8c042 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,8 +1,11 @@ -error: expected expression, found reserved keyword `try` - --> $DIR/try-block-in-while.rs:6:11 +error[E0277]: the trait bound `bool: std::ops::Try` is not satisfied + --> $DIR/try-block-in-while.rs:6:15 | LL | while try { false } {} - | ^^^ expected expression + | ^^^^^^^^^ the trait `std::ops::Try` is not implemented for `bool` + | + = note: required by `std::ops::Try::from_ok` error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-block/try-block-unused-delims.rs b/src/test/ui/try-block/try-block-unused-delims.rs new file mode 100644 index 0000000000000..0b767eb2dad77 --- /dev/null +++ b/src/test/ui/try-block/try-block-unused-delims.rs @@ -0,0 +1,28 @@ +// check-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] +#![warn(unused_parens, unused_braces)] + +fn consume(_: Result) -> T { todo!() } + +fn main() { + consume((try {})); + //~^ WARN unnecessary parentheses + + consume({ try {} }); + //~^ WARN unnecessary braces + + match (try {}) { + //~^ WARN unnecessary parentheses + Ok(()) | Err(()) => (), + } + + if let Err(()) = (try {}) {} + //~^ WARN unnecessary parentheses + + match (try {}) { + //~^ WARN unnecessary parentheses + Ok(()) | Err(()) => (), + } +} diff --git a/src/test/ui/try-block/try-block-unused-delims.stderr b/src/test/ui/try-block/try-block-unused-delims.stderr new file mode 100644 index 0000000000000..5c7602ee0ab12 --- /dev/null +++ b/src/test/ui/try-block/try-block-unused-delims.stderr @@ -0,0 +1,44 @@ +warning: unnecessary parentheses around function argument + --> $DIR/try-block-unused-delims.rs:10:13 + | +LL | consume((try {})); + | ^^^^^^^^ help: remove these parentheses + | +note: the lint level is defined here + --> $DIR/try-block-unused-delims.rs:5:9 + | +LL | #![warn(unused_parens, unused_braces)] + | ^^^^^^^^^^^^^ + +warning: unnecessary braces around function argument + --> $DIR/try-block-unused-delims.rs:13:13 + | +LL | consume({ try {} }); + | ^^^^^^^^^^ help: remove these braces + | +note: the lint level is defined here + --> $DIR/try-block-unused-delims.rs:5:24 + | +LL | #![warn(unused_parens, unused_braces)] + | ^^^^^^^^^^^^^ + +warning: unnecessary parentheses around `match` scrutinee expression + --> $DIR/try-block-unused-delims.rs:16:11 + | +LL | match (try {}) { + | ^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around `let` scrutinee expression + --> $DIR/try-block-unused-delims.rs:21:22 + | +LL | if let Err(()) = (try {}) {} + | ^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around `match` scrutinee expression + --> $DIR/try-block-unused-delims.rs:24:11 + | +LL | match (try {}) { + | ^^^^^^^^ help: remove these parentheses + +warning: 5 warnings emitted +