diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index fdd8784453bdb..cd48e6aa4c4ba 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -79,8 +79,8 @@ def _download(path, url, probably_big, verbose, exception): # see http://serverfault.com/questions/301128/how-to-download if sys.platform == 'win32': run(["PowerShell.exe", "/nologo", "-Command", - "(New-Object System.Net.WebClient)" - ".DownloadFile('{}', '{}')".format(url, path)], + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)], verbose=verbose, exception=exception) else: diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cef0849937bf0..c8689f7814086 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -203,7 +203,7 @@ impl Step for StdLink { /// Link all libstd rlibs/dylibs into the sysroot location. /// - /// Links those artifacts generated by `compiler` to a the `stage` compiler's + /// Links those artifacts generated by `compiler` to the `stage` compiler's /// sysroot for the specified `host` and `target`. /// /// Note that this assumes that `compiler` has already generated the libstd diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 296422744fa40..61e5b3d0133ff 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -186,6 +186,9 @@ mod bar { Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. +One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will +not eagerly inline it as a module unless you add `#[doc(inline)}`. + ## `#[doc(hidden)]` Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index 24a0ce0ac3611..b0220c84ef2fa 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -12,7 +12,7 @@ # containing LLDB commands (one command per line), this script will execute the commands one after # the other. # LLDB also has the -s and -S commandline options which also execute a list of commands from a text -# file. However, this command are execute `immediately`: a the command of a `run` or `continue` +# file. However, this command are execute `immediately`: the command of a `run` or `continue` # command will be executed immediately after the `run` or `continue`, without waiting for the next # breakpoint to be hit. This a command sequence like the following will not yield reliable results: # diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 3bd0c243b39ac..1a8a081e16fad 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -21,6 +21,10 @@ use core::usize; pub use core::alloc::*; extern "Rust" { + // These are the magic symbols to call the global allocator. rustc generates + // them from the `#[global_allocator]` attribute if there is one, or uses the + // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`) + // otherwise. #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 74354f605e537..63b262d1f3d98 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -73,7 +73,7 @@ use core::convert::From; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -use core::iter::FusedIterator; +use core::iter::{Iterator, FromIterator, FusedIterator}; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; @@ -81,6 +81,7 @@ use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, Gene use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; +use vec::Vec; use raw_vec::RawVec; use str::from_boxed_utf8_unchecked; @@ -699,6 +700,13 @@ impl, U: ?Sized> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "0")] impl, U: ?Sized> DispatchFromDyn> for Box {} +#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")] +impl FromIterator for Box<[A]> { + fn from_iter>(iter: T) -> Self { + iter.into_iter().collect::>().into_boxed_slice() + } +} + #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<[T]> { fn clone(&self) -> Self { diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 55995742a4a7d..f340ea01c5f07 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -140,3 +140,11 @@ fn str_slice() { let boxed: Box = Box::from(s); assert_eq!(&*boxed, s) } + +#[test] +fn boxed_slice_from_iter() { + let iter = 0..100; + let boxed: Box<[u32]> = iter.collect(); + assert_eq!(boxed.len(), 100); + assert_eq!(boxed[7], 7); +} diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 24c8fd3a969ca..49e488702b4b9 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -853,9 +853,10 @@ impl BTreeMap { /// ``` /// use std::collections::BTreeMap; /// - /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter() - /// .map(|&s| (s, 0)) - /// .collect(); + /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"] + /// .iter() + /// .map(|&s| (s, 0)) + /// .collect(); /// for (_, balance) in map.range_mut("B".."Cheryl") { /// *balance += 100; /// } diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 5c776292f53d7..2beb3240aaca0 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2206,6 +2206,20 @@ impl<'a> From<&'a str> for String { #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { + /// Converts the given boxed `str` slice to a `String`. + /// It is notable that the `str` slice is owned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1: String = String::from("hello world"); + /// let s2: Box = s1.into_boxed_str(); + /// let s3: String = String::from(s2); + /// + /// assert_eq!("hello world", s3) + /// ``` fn from(s: Box) -> String { s.into_string() } @@ -2213,6 +2227,19 @@ impl From> for String { #[stable(feature = "box_from_str", since = "1.20.0")] impl From for Box { + /// Converts the given `String` to a boxed `str` slice that is owned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1: String = String::from("hello world"); + /// let s2: Box = Box::from(s1); + /// let s3: String = String::from(s2); + /// + /// assert_eq!("hello world", s3) + /// ``` fn from(s: String) -> Box { s.into_boxed_str() } @@ -2272,6 +2299,20 @@ impl<'a> FromIterator for Cow<'a, str> { #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] impl From for Vec { + /// Converts the given `String` to a vector `Vec` that holds values of type `u8`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s1 = String::from("hello world"); + /// let v1 = Vec::from(s1); + /// + /// for b in v1 { + /// println!("{}", b); + /// } + /// ``` fn from(string: String) -> Vec { string.into_bytes() } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7ed6e4a8f51eb..68d52cecf5fae 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -714,6 +714,10 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; + /// Moves a value out of scope without running drop glue. + #[cfg(not(stage0))] + pub fn forget(_: T); + /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index c69d4441121ce..f328af71bd134 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -107,6 +107,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(unboxed_closures)] +#![feature(unsized_locals)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] @@ -129,6 +130,7 @@ #![feature(const_transmute)] #![feature(reverse_bits)] #![feature(non_exhaustive)] +#![feature(structural_match)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 662a8ddd96862..3bcdfabbb245e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -578,6 +578,7 @@ macro_rules! impls{ /// /// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] +#[structural_match] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8c4ff02aa140f..5fcf428975769 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -143,6 +143,19 @@ pub fn forget(t: T) { ManuallyDrop::new(t); } +/// Like [`forget`], but also accepts unsized values. +/// +/// This function is just a shim intended to be removed when the `unsized_locals` feature gets +/// stabilized. +/// +/// [`forget`]: fn.forget.html +#[inline] +#[cfg(not(stage0))] +#[unstable(feature = "forget_unsized", issue = "0")] +pub fn forget_unsized(t: T) { + unsafe { intrinsics::forget(t) } +} + /// Returns the size of a type in bytes. /// /// More specifically, this is the offset in bytes between successive elements diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index a2782dd8e2e43..fe383712f64c4 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1896,7 +1896,7 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { // is_char_boundary checks that the index is in [0, .len()] - // canot reuse `get` as above, because of NLL trouble + // cannot reuse `get` as above, because of NLL trouble if self.start <= self.end && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index f2825887f36e2..0114f9e9321e1 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -132,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// /// See the `region_obligations` field of `InferCtxt` for some /// comments about how this function fits into the overall expected - /// flow of the the inferencer. The key point is that it is + /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// towards the end of regionck. This also ensures that the /// region-bound-pairs are available (see comments above regarding diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 5470aff77f8a4..8acbaaa844d74 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1020,9 +1020,12 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_pat(&mut self, p: &'a ast::Pat) { - run_lints!(self, check_pat, p); + let mut visit_subpats = true; + run_lints!(self, check_pat, p, &mut visit_subpats); self.check_id(p.id); - ast_visit::walk_pat(self, p); + if visit_subpats { + ast_visit::walk_pat(self, p); + } } fn visit_expr(&mut self, e: &'a ast::Expr) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index afd7800810982..18922ec5d1739 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -341,7 +341,7 @@ pub trait EarlyLintPass: LintPass { fn check_block_post(&mut self, _: &EarlyContext<'_>, _: &ast::Block) { } fn check_stmt(&mut self, _: &EarlyContext<'_>, _: &ast::Stmt) { } fn check_arm(&mut self, _: &EarlyContext<'_>, _: &ast::Arm) { } - fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat) { } + fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat, _: &mut bool) { } fn check_expr(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_expr_post(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_ty(&mut self, _: &EarlyContext<'_>, _: &ast::Ty) { } diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index f21f949c9f5cd..781a0fa3f663a 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -62,16 +62,6 @@ macro_rules! span_bug { }) } -#[macro_export] -macro_rules! static_assert { - ($name:ident: $test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - static $name: () = [()][!$test as usize]; - } -} - #[macro_export] macro_rules! __impl_stable_hash_field { ($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher)); diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index e55997099c82b..cc92b63256c1f 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -65,6 +65,17 @@ pub trait AllocationExtra: ::std::fmt::Debug + Default + Clone { ) -> EvalResult<'tcx> { Ok(()) } + + /// Hook for performing extra checks on a memory deallocation. + /// `size` will be the size of the allocation. + #[inline] + fn memory_deallocated( + _alloc: &mut Allocation, + _ptr: Pointer, + _size: Size, + ) -> EvalResult<'tcx> { + Ok(()) + } } impl AllocationExtra<()> for () {} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8a32e8f46c290..73800074cc7e8 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1719,14 +1719,14 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } +// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::>() == 56); + impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { - // `Statement` contributes significantly to peak memory usage. Make - // sure it doesn't get bigger. - static_assert!(STATEMENT_IS_AT_MOST_56_BYTES: mem::size_of::>() <= 56); - self.kind = StatementKind::Nop } @@ -2611,7 +2611,7 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Resu _ => {} } } - // print function definitons + // print function definitions if let FnDef(did, _) = ty.sty { return write!(f, "{}", item_path_str(did)); } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index a1e2b7a06468d..f3a0b7de90374 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // // It does the actual traversal of the graph, while the `next` method on the iterator // just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and - // iterators over the sucessors of those nodes. Each iteration attempts to get the next + // iterators over the successors of those nodes. Each iteration attempts to get the next // node from the top of the stack, then pushes that node and an iterator over the // successors to the top of the stack. This loop only grows `visit_stack`, stopping when // we reach a child that has no children that we haven't already visited. @@ -163,7 +163,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // The state of the stack starts out with just the root node (`A` in this case); // [(A, [B, C])] // - // When the first call to `traverse_sucessor` happens, the following happens: + // When the first call to `traverse_successor` happens, the following happens: // // [(B, [D]), // `B` taken from the successors of `A`, pushed to the // // top of the stack along with the successors of `B` diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 82095a2f5b01d..f78fad9f7aa9a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -823,12 +823,6 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - // Ensure our type representation does not grow - #[cfg(target_pointer_width = "64")] - static_assert!(ASSERT_TY_KIND: ::std::mem::size_of::>() <= 24); - #[cfg(target_pointer_width = "64")] - static_assert!(ASSERT_TYS: ::std::mem::size_of::>() <= 32); - let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); let mk_region = |r| { if let Some(r) = interners.region.borrow().get(&r) { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9a63bb374c66d..979cc9b115b5a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -514,6 +514,10 @@ pub struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } +// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::>() == 32); + impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { self.sty.cmp(&other.sty) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index ed7b2cffc46f6..27eafa7ab580f 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -291,7 +291,8 @@ define_queries! { <'tcx> /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) + -> Lrc, /// Checks all types in the krate for overlap in their inherent impls. Reports errors. /// Not meant to be used directly outside of coherence. diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 8bbfd92d688ed..efee39a1d63f9 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -100,7 +100,7 @@ pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { } impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { - /// Either gets a JobOwner corresponding the the query, allowing us to + /// Either gets a JobOwner corresponding the query, allowing us to /// start executing the query, or it returns with the result of the query. /// If the query is executing elsewhere, this will wait for it. /// If the query panicked, this will silently panic. @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Try to read a node index for the node dep_node. /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when - /// the a node index can be found for that node. + /// a node index can be found for that node. pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option { match self.dep_graph.node_color(dep_node) { Some(DepNodeColor::Green(dep_node_index)) => { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a4130bf15cb82..bd3a34cae90f4 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -211,6 +211,10 @@ pub enum TyKind<'tcx> { Error, } +// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::>() == 24); + /// A closure can be modeled as a struct that looks like: /// /// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> { diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 4f405858e350c..adcb9857ee3c2 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -895,7 +895,7 @@ impl Float for IeeeFloat { } // The intermediate result of the multiplication has "2 * S::PRECISION" - // signicant bit; adjust the addend to be consistent with mul result. + // significant bit; adjust the addend to be consistent with mul result. let mut ext_addend_sig = [addend.sig[0], 0]; // Extend the addend significand to ext_precision - 1. This guarantees @@ -920,7 +920,7 @@ impl Float for IeeeFloat { // Convert the result having "2 * S::PRECISION" significant-bits back to the one // having "S::PRECISION" significant-bits. First, move the radix point from - // poision "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be + // position "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be // adjusted by "2*S::PRECISION - 1" - "S::PRECISION - 1" = "S::PRECISION". self.exp -= S::PRECISION as ExpInt + 1; diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index a5f90149f4ac4..8f79d49b3e2b4 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -194,7 +194,7 @@ pub fn codegen_intrinsic_call( return; } // Effectively no-ops - "uninit" => { + "uninit" | "forget" => { return; } "needs_drop" => { diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index eaa599e0cd0fa..267d7e0d54b63 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -184,7 +184,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ ]; /// When rustdoc is running, provide a list of all known features so that all their respective -/// primtives may be documented. +/// primitives may be documented. /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! diff --git a/src/librustc_codegen_utils/linker.rs b/src/librustc_codegen_utils/linker.rs index ae1d77f152189..e9ac92da68435 100644 --- a/src/librustc_codegen_utils/linker.rs +++ b/src/librustc_codegen_utils/linker.rs @@ -613,7 +613,7 @@ impl<'a> Linker for MsvcLinker<'a> { // from the CodeView line tables in the object files. self.cmd.arg("/DEBUG"); - // This will cause the Microsoft linker to embed .natvis info into the the PDB file + // This will cause the Microsoft linker to embed .natvis info into the PDB file let sysroot = self.sess.sysroot(); let natvis_dir_path = sysroot.join("lib\\rustlib\\etc"); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 07e5548216f3c..135abebdacb7a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -57,6 +57,7 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; +pub mod macros; pub mod svh; pub mod base_n; pub mod bit_set; diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs new file mode 100644 index 0000000000000..3cc91b0e93f04 --- /dev/null +++ b/src/librustc_data_structures/macros.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A simple static assertion macro. The first argument should be a unique +/// ALL_CAPS identifier that describes the condition. +#[macro_export] +macro_rules! static_assert { + ($name:ident: $test:expr) => { + // Use the bool to access an array such that if the bool is false, the access + // is out-of-bounds. + #[allow(dead_code)] + static $name: () = [()][!$test as usize]; + } +} diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index dee50f5ab2679..2a8a0baf571b0 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -490,7 +490,7 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(),()> { } } -/// Allocate a the lock-file and lock it. +/// Allocate the lock-file and lock it. fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2a9b58200e5d6..696fee04273fd 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -40,6 +40,8 @@ use rustc::util::nodemap::FxHashSet; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; +use syntax::ptr::P; +use syntax::ast::Expr; use syntax::attr; use syntax::source_map::Spanned; use syntax::edition::Edition; @@ -47,6 +49,7 @@ use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_a use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; use syntax::errors::{Applicability, DiagnosticBuilder}; +use syntax::print::pprust::expr_to_string; use rustc::hir::{self, GenericParamKind, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1407,21 +1410,48 @@ impl LintPass for EllipsisInclusiveRangePatterns { } impl EarlyLintPass for EllipsisInclusiveRangePatterns { - fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) { - use self::ast::{PatKind, RangeEnd, RangeSyntax}; + fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat, visit_subpats: &mut bool) { + use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot}; + + /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span + /// corresponding to the ellipsis. + fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P, &P, Span)> { + match &pat.node { + PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => { + Some((a, b, *span)) + } + _ => None, + } + } - if let PatKind::Range( - _, _, Spanned { span, node: RangeEnd::Included(RangeSyntax::DotDotDot) } - ) = pat.node { + let (parenthesise, endpoints) = match &pat.node { + PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)), + _ => (false, matches_ellipsis_pat(pat)), + }; + + if let Some((start, end, join)) = endpoints { let msg = "`...` range patterns are deprecated"; - let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg); - err.span_suggestion_short_with_applicability( - span, "use `..=` for an inclusive range", "..=".to_owned(), - // FIXME: outstanding problem with precedence in ref patterns: - // https://github.com/rust-lang/rust/issues/51043#issuecomment-392252285 - Applicability::MaybeIncorrect - ); - err.emit() + let suggestion = "use `..=` for an inclusive range"; + if parenthesise { + *visit_subpats = false; + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg); + err.span_suggestion_with_applicability( + pat.span, + suggestion, + format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)), + Applicability::MachineApplicable, + ); + err.emit(); + } else { + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg); + err.span_suggestion_short_with_applicability( + join, + suggestion, + "..=".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); + }; } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 6d365e6d1ecbf..7eab7d2100290 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -396,12 +396,12 @@ impl EarlyLintPass for UnusedParens { self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } - fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) { + fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat, _: &mut bool) { use ast::PatKind::{Paren, Range}; // The lint visitor will visit each subpattern of `p`. We do not want to lint any range // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there // is a recursive `check_pat` on `a` and `b`, but we will assume that if there are - // unnecessry parens they serve a purpose of readability. + // unnecessary parens they serve a purpose of readability. if let Paren(ref pat) = p.node { match pat.node { Range(..) => {} diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs index 91008e8f9690e..b3e159dd84457 100644 --- a/src/librustc_mir/borrow_check/location.rs +++ b/src/librustc_mir/borrow_check/location.rs @@ -11,7 +11,7 @@ use rustc::mir::{BasicBlock, Location, Mir}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -/// Maps between a MIR Location, which identifies the a particular +/// Maps between a MIR Location, which identifies a particular /// statement within a basic block, to a "rich location", which /// identifies at a finer granularity. In particular, we distinguish /// the *start* of a statement and the *mid-point*. The mid-point is diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 3607ae4f5088d..2b7ef38d3edf9 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -112,7 +112,7 @@ impl RegionValueElements { } = self.to_location(index); if statement_index == 0 { // If this is a basic block head, then the predecessors are - // the the terminators of other basic blocks + // the terminators of other basic blocks stack.extend( mir.predecessors_for(block) .iter() diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index aa383a123b69a..2ef71617b7cb6 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = this.source_info(span); for stmt in stmts { - let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt); + let Stmt { kind, opt_destruction_scope, span: stmt_span } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let si = (scope, source_info); this.in_scope(si, LintLevel::Inherited, block, |this| { let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) + this.stmt_expr(block, expr, Some(stmt_span)) }) })); } @@ -177,17 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || - match this.block_context.last() { - // no context: conservatively assume result is read - None => false, - - // sub-expression: block result feeds into some computation - Some(BlockFrame::SubExpr) => false, - - // otherwise: use accumualated is_ignored state. - Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | - Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, - }; + this.block_context.currently_ignores_tail_results(); this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored }); unpack!(block = this.into(destination, block, expr)); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8fee74390cc6b..18ce7ae490708 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(adt, fields)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr)); + block = unpack!(this.stmt_expr(block, expr, None)); block.and(this.unit_rvalue()) } ExprKind::Yield { value } => { diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index e0bf02c6739e3..8f50a1e9a21b9 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -10,7 +10,7 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::middle::region; use rustc::mir::*; @@ -68,19 +68,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); // Find out whether this temp is being created within the // tail expression of a block whose result is ignored. - for bf in this.block_context.iter().rev() { - match bf { - BlockFrame::SubExpr => continue, - BlockFrame::Statement { .. } => break, - &BlockFrame::TailExpr { tail_result_is_ignored } => { - local_decl = local_decl.block_tail(BlockTailInfo { - tail_result_is_ignored - }); - break; - } - } + if let Some(tail_info) = this.block_context.currently_in_block_tail() { + local_decl = local_decl.block_tail(tail_info); } - this.local_decls.push(local_decl) }; if !expr_ty.is_never() { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d2913872fca45..8eb46a0483917 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Break { .. } | ExprKind::InlineAsm { .. } | ExprKind::Return { .. } => { - unpack!(block = this.stmt_expr(block, expr)); + unpack!(block = this.stmt_expr(block, expr, None)); this.cfg.push_assign_unit(block, source_info, destination); block.unit() } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8f52499124ab7..45235b3153934 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -14,7 +14,18 @@ use hair::*; use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> { + /// Builds a block of MIR statements to evaluate the HAIR `expr`. + /// If the original expression was an AST statement, + /// (e.g. `some().code(&here());`) then `opt_stmt_span` is the + /// span of that statement (including its semicolon, if any). + /// Diagnostics use this span (which may be larger than that of + /// `expr`) to identify when statement temporaries are dropped. + pub fn stmt_expr(&mut self, + mut block: BasicBlock, + expr: Expr<'tcx>, + opt_stmt_span: Option) + -> BlockAnd<()> + { let this = self; let expr_span = expr.span; let source_info = this.source_info(expr.span); @@ -29,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } => { let value = this.hir.mirror(value); this.in_scope((region_scope, source_info), lint_level, block, |this| { - this.stmt_expr(block, value) + this.stmt_expr(block, value, opt_stmt_span) }) } ExprKind::Assign { lhs, rhs } => { @@ -190,9 +201,56 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone(), expr_span); + + // Issue #54382: When creating temp for the value of + // expression like: + // + // `{ side_effects(); { let l = stuff(); the_value } }` + // + // it is usually better to focus on `the_value` rather + // than the entirety of block(s) surrounding it. + let mut temp_span = expr_span; + let mut temp_in_tail_of_block = false; + if let ExprKind::Block { body } = expr.kind { + if let Some(tail_expr) = &body.expr { + let mut expr = tail_expr; + while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { + if let Some(subtail_expr) = &subblock.expr { + expr = subtail_expr + } else { + break; + } + } + temp_span = expr.span; + temp_in_tail_of_block = true; + } + } + + let temp = { + let mut local_decl = LocalDecl::new_temp(expr.ty.clone(), temp_span); + if temp_in_tail_of_block { + if this.block_context.currently_ignores_tail_results() { + local_decl = local_decl.block_tail(BlockTailInfo { + tail_result_is_ignored: true + }); + } + } + let temp = this.local_decls.push(local_decl); + let place = Place::Local(temp); + debug!("created temp {:?} for expr {:?} in block_context: {:?}", + temp, expr, this.block_context); + place + }; unpack!(block = this.into(&temp, block, expr)); - unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); + + // Attribute drops of the statement's temps to the + // semicolon at the statement's end. + let drop_point = this.hir.tcx().sess.source_map().end_point(match opt_stmt_span { + None => expr_span, + Some(StatementSpan(span)) => span, + }); + + unpack!(block = this.build_drop(block, drop_point, temp, expr_ty)); block.unit() } } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5b4001f0652ad..a01f8940a948a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -336,6 +336,9 @@ impl BlockFrame { } } +#[derive(Debug)] +struct BlockContext(Vec); + struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { hir: Cx<'a, 'gcx, 'tcx>, cfg: CFG<'tcx>, @@ -359,7 +362,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// start just throwing new entries onto that vector in order to /// distinguish the context of EXPR1 from the context of EXPR2 in /// `{ STMTS; EXPR1 } + EXPR2` - block_context: Vec, + block_context: BlockContext, /// The current unsafe block in scope, even if it is hidden by /// a PushUnsafeBlock @@ -409,6 +412,55 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } +impl BlockContext { + fn new() -> Self { BlockContext(vec![]) } + fn push(&mut self, bf: BlockFrame) { self.0.push(bf); } + fn pop(&mut self) -> Option { self.0.pop() } + + /// Traverses the frames on the BlockContext, searching for either + /// the first block-tail expression frame with no intervening + /// statement frame. + /// + /// Notably, this skips over `SubExpr` frames; this method is + /// meant to be used in the context of understanding the + /// relationship of a temp (created within some complicated + /// expression) with its containing expression, and whether the + /// value of that *containing expression* (not the temp!) is + /// ignored. + fn currently_in_block_tail(&self) -> Option { + for bf in self.0.iter().rev() { + match bf { + BlockFrame::SubExpr => continue, + BlockFrame::Statement { .. } => break, + &BlockFrame::TailExpr { tail_result_is_ignored } => + return Some(BlockTailInfo { tail_result_is_ignored }) + } + } + + return None; + } + + /// Looks at the topmost frame on the BlockContext and reports + /// whether its one that would discard a block tail result. + /// + /// Unlike `currently_within_ignored_tail_expression`, this does + /// *not* skip over `SubExpr` frames: here, we want to know + /// whether the block result itself is discarded. + fn currently_ignores_tail_results(&self) -> bool { + match self.0.last() { + // no context: conservatively assume result is read + None => false, + + // sub-expression: block result feeds into some computation + Some(BlockFrame::SubExpr) => false, + + // otherwise: use accumulated is_ignored state. + Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | + Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, + } + } +} + #[derive(Debug)] enum LocalsForNode { /// In the usual case, a node-id for an identifier maps to at most @@ -764,7 +816,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn_span: span, arg_count, scopes: vec![], - block_context: vec![], + block_context: BlockContext::new(), source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, source_scope_local_data: IndexVec::new(), diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 586d6d87fa0dc..d56ddcb494406 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -57,6 +57,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, for (index, stmt) in stmts.iter().enumerate() { let hir_id = cx.tcx.hir.node_to_hir_id(stmt.node.id()); let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); + let stmt_span = StatementSpan(cx.tcx.hir.span(stmt.node.id())); match stmt.node { hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => { @@ -69,6 +70,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: expr.to_ref(), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))) } hir::StmtKind::Decl(ref decl, _) => { @@ -111,6 +113,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, lint_level: cx.lint_level_of(local.id), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))); } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8a24851de8149..fd1ddcc1cc6ca 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -71,10 +71,14 @@ pub enum StmtRef<'tcx> { Mirror(Box>), } +#[derive(Clone, Debug)] +pub struct StatementSpan(pub Span); + #[derive(Clone, Debug)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, pub opt_destruction_scope: Option, + pub span: StatementSpan, } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6267012dc275..ca09857bbd5ff 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -341,8 +341,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1)?; - let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)? - .expect("Fields cannot be extern types"); + let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { + Some(size_and_align) => size_and_align, + None => { + // A field with extern type. If this field is at offset 0, we behave + // like the underlying extern type. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + if sized_size == Size::ZERO { + return Ok(None) + } else { + bug!("Fields cannot be extern types, unless they are at offset 0") + } + } + }; // FIXME (#26403, #27023): We should be adding padding // to `sized_size` (to accommodate the `unsized_align` diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 047996777ea96..1efd7ca7f8973 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -17,7 +17,7 @@ use std::hash::Hash; use rustc::hir::{self, def_id::DefId}; use rustc::mir; -use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt}; +use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt}; use super::{ Allocation, AllocId, EvalResult, Scalar, AllocationExtra, @@ -174,16 +174,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { dest: PlaceTy<'tcx, Self::PointerTag>, ) -> EvalResult<'tcx>; - /// Hook for performing extra checks when memory gets deallocated. - #[inline] - fn memory_deallocated( - _alloc: &mut Allocation, - _ptr: Pointer, - _size: Size, - ) -> EvalResult<'tcx> { - Ok(()) - } - /// Add the tag for a newly allocated pointer. fn tag_new_allocation( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 10bc984a447a3..e125927e7d273 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Let the machine take some extra action let size = Size::from_bytes(alloc.bytes.len() as u64); - M::memory_deallocated(&mut alloc, ptr, size)?; + AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?; // Don't forget to remember size and align of this now-dead allocation let old = self.dead_alloc_map.insert( diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6f8bbf3c4a97d..b2f8959eba95f 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -346,8 +346,17 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let (_, align) = self.size_and_align_of(base.meta, field_layout)? - .expect("Fields cannot be extern types"); + let align = match self.size_and_align_of(base.meta, field_layout)? { + Some((_, align)) => align, + None if offset == Size::ZERO => + // An extern type at offset 0, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + field_layout.align, + None => + bug!("Cannot compute offset for extern type field at non-0 offset"), + }; (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9bc3fbe7c245a..0c0f50c1fd709 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1254,21 +1254,25 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { Vec::new() }; - let sub_span = - self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star)); - if !self.span.filter_generated(use_tree.span) { - let span = - self.span_from_span(sub_span.expect("No span found for use glob")); - self.dumper.import(&access, Import { - kind: ImportKind::GlobUse, - ref_id: None, - span, - alias_span: None, - name: "*".to_owned(), - value: names.join(", "), - parent, - }); - self.write_sub_paths(&path); + // Otherwise it's a span with wrong macro expansion info, which + // we don't want to track anyway, since it's probably macro-internal `use` + if let Some(sub_span) = + self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star)) + { + if !self.span.filter_generated(use_tree.span) { + let span = self.span_from_span(sub_span); + + self.dumper.import(&access, Import { + kind: ImportKind::GlobUse, + ref_id: None, + span, + alias_span: None, + name: "*".to_owned(), + value: names.join(", "), + parent, + }); + self.write_sub_paths(&path); + } } } ast::UseTreeKind::Nested(ref nested_items) => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 84967aaf72f57..9aad17626f9a1 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -134,6 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), + "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7dfdb926c60ef..091af449095aa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -548,7 +548,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// current expression. As each subpart is processed, they may set /// the flag to `Always` etc. Finally, at the end, we take the /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the the parent + /// return the flag indicates if any subpart of the parent /// expression (up to and including this part) has diverged. So, /// if you read it after evaluating a subexpression `X`, the value /// you get indicates whether any subexpression that was diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index ec979dea4fd03..370f8857f1400 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -31,7 +31,7 @@ use syntax_pos::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) - -> CrateInherentImpls { + -> Lrc { assert_eq!(crate_num, LOCAL_CRATE); let krate = tcx.hir.krate(); @@ -42,7 +42,7 @@ pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; krate.visit_all_item_likes(&mut collect); - collect.impls_map + Lrc::new(collect.impls_map) } /// On-demand query: yields a vector of the inherent impls for a specific type. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c39b71e33ca0c..5a020749f3577 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3499,13 +3499,16 @@ impl Clean> for doctree::Import { // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { + let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { a.name() == "doc" && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, "no_inline") || attr::list_contains_name(&l, "hidden"), None => false, } }); + // Also check whether imports were asked to be inlined, in case we're trying to re-export a + // crate in Rust 2018+ + let please_inline = self.attrs.lists("doc").has_word("inline"); let path = self.path.clean(cx); let inner = if self.glob { if !denied { @@ -3518,6 +3521,16 @@ impl Clean> for doctree::Import { Import::Glob(resolve_use_source(cx, path)) } else { let name = self.name; + if !please_inline { + match path.def { + Def::Mod(did) => if !did.is_local() && did.index == CRATE_DEF_INDEX { + // if we're `pub use`ing an extern crate root, don't inline it unless we + // were specifically asked for it + denied = true; + } + _ => {} + } + } if !denied { let mut visited = FxHashSet::default(); if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) { diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 485b2ffe1975e..9c0573964702e 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -142,6 +142,7 @@ pub use alloc_crate::alloc::*; #[derive(Debug, Copy, Clone)] pub struct System; +// The Alloc impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] @@ -226,6 +227,10 @@ pub fn rust_oom(layout: Layout) -> ! { #[unstable(feature = "alloc_internals", issue = "0")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; + // These magic symbol names are used as a fallback for implementing the + // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs) when there is + // no `#[global_allocator]` attribute. + // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 96c92ceb5bb41..15fbb10592133 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -16,7 +16,7 @@ /// The entry point for panic of Rust threads. /// -/// This allows a program to to terminate immediately and provide feedback +/// This allows a program to terminate immediately and provide feedback /// to the caller of the program. `panic!` should be used when a program reaches /// an unrecoverable problem. /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a9219f75362db..327ad7f64c23f 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -764,14 +764,15 @@ impl Command { /// /// ```should_panic /// use std::process::Command; + /// use std::io::{self, Write}; /// let output = Command::new("/bin/cat") /// .arg("file.txt") /// .output() /// .expect("failed to execute process"); /// /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + /// io::stdout().write_all(&output.stdout).unwrap(); + /// io::stderr().write_all(&output.stderr).unwrap(); /// /// assert!(output.status.success()); /// ``` @@ -951,6 +952,7 @@ impl Stdio { /// /// ```no_run /// use std::process::{Command, Stdio}; + /// use std::io::{self, Write}; /// /// let output = Command::new("rev") /// .stdin(Stdio::inherit()) @@ -958,7 +960,8 @@ impl Stdio { /// .output() /// .expect("Failed to execute command"); /// - /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); + /// print!("You piped in the reverse of: "); + /// io::stdout().write_all(&output.stdout).unwrap(); /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index f41bd2c20720a..a5a93908b494d 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -135,14 +135,15 @@ impl Command { Some(envp) => { match envp.get_items().iter().find(|var| var.as_bytes().starts_with(b"PATH=")) { Some(p) => &p.as_bytes()[5..], - None => return None, + // Chosen to match what glibc does if there's no PATH variable + None => b"/bin:/usr/bin", } }, // maybe_envp is None if the process isn't changing the parent's env at all. None => { match parent_path.as_ref() { Some(p) => p.as_bytes(), - None => return None, + None => b"/bin:/usr/bin", } }, }; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2f17bc0548cad..fa6fe34783389 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,6 +20,7 @@ use print::pprust; use ptr::P; use rustc_data_structures::indexed_vec; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::static_assert; use rustc_target::spec::abi::Abi; use source_map::{dummy_spanned, respan, Spanned}; use symbol::{keywords, Symbol}; @@ -924,6 +925,10 @@ pub struct Expr { pub attrs: ThinVec, } +// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 88); + impl Expr { /// Whether this expression would be valid somewhere that expects a value, for example, an `if` /// condition. diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 7a0a764d4639a..f31d80acbfa4e 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -122,7 +122,7 @@ impl<'tt> TokenTreeOrTokenTreeSlice<'tt> { } } - /// The the `index`-th token tree of `self`. + /// The `index`-th token tree of `self`. fn get_tt(&self, index: usize) -> TokenTree { match *self { TtSeq(ref v) => v[index].clone(), diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 74363f3e5f7d9..218486748315d 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -496,7 +496,7 @@ where return (None, KleeneOp::ZeroOrMore); } - // #2 is a Kleene op, which is the the only valid option + // #2 is a Kleene op, which is the only valid option Ok(Ok((op, _))) => { // Warn that `?` as a separator will be deprecated sess.buffer_lint( diff --git a/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs index 9fa0b40d49c20..e519d48ac1d4d 100644 --- a/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs @@ -31,7 +31,7 @@ struct CheckId { v: T } // In the code below, the impl of HasId for `&'a usize` does not // actually access the borrowed data, but the point is that the // interface to CheckId does not (and cannot) know that, and therefore -// when encountering the a value V of type CheckId, we must +// when encountering a value V of type CheckId, we must // conservatively force the type S to strictly outlive V. impl Drop for CheckId { fn drop(&mut self) { diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index 96f9da67790fc..0352161d7ddff 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -55,6 +55,16 @@ fn main() { println!("passed"); } + "exec-test6" => { + let err = Command::new("echo").arg("passed").env_clear().exec(); + panic!("failed to spawn: {}", err); + } + + "exec-test7" => { + let err = Command::new("echo").arg("passed").env_remove("PATH").exec(); + panic!("failed to spawn: {}", err); + } + _ => panic!("unknown argument: {}", arg), } return @@ -84,4 +94,14 @@ fn main() { assert!(output.status.success()); assert!(output.stderr.is_empty()); assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test6").output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test7").output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); } diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs new file mode 100644 index 0000000000000..55202de1981be --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod asdf { + pub struct SomeStruct; +} + +pub trait SomeTrait {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs new file mode 100644 index 0000000000000..1f11cbc4da718 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct SomethingElse; diff --git a/src/test/rustdoc/inline_cross/use_crate.rs b/src/test/rustdoc/inline_cross/use_crate.rs new file mode 100644 index 0000000000000..a98704446ee76 --- /dev/null +++ b/src/test/rustdoc/inline_cross/use_crate.rs @@ -0,0 +1,37 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:use_crate.rs +// aux-build:use_crate_2.rs +// build-aux-docs +// edition:2018 +// compile-flags:--extern use_crate --extern use_crate_2 -Z unstable-options + +// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it +// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement +// in docs... unless you added `#[doc(inline)]`. + +#![crate_name = "local"] + +// @!has-dir local/use_crate +// @has local/index.html +// @has - '//code' 'pub use use_crate' +pub use use_crate; + +// @has-dir local/asdf +// @has local/asdf/index.html +// @has local/index.html '//a/@href' 'asdf/index.html' +pub use use_crate::asdf; + +// @has-dir local/use_crate_2 +// @has local/use_crate_2/index.html +// @has local/index.html '//a/@href' 'use_crate_2/index.html' +#[doc(inline)] +pub use use_crate_2; diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs index d3307bb4d42c1..6cc7f1743ad07 100644 --- a/src/test/rustdoc/src-links-external.rs +++ b/src/test/rustdoc/src-links-external.rs @@ -18,6 +18,7 @@ extern crate src_links_external; // @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' +#[doc(inline)] pub use src_links_external as bar; // @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11' diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs new file mode 100644 index 0000000000000..611fb89341de4 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -0,0 +1,27 @@ +// compile-pass + +// Test that we can handle newtypes wrapping extern types + +#![feature(extern_types, const_transmute)] + +use std::marker::PhantomData; + +extern "C" { + pub type ExternType; +} +unsafe impl Sync for ExternType {} +static MAGIC_FFI_STATIC: u8 = 42; + +#[repr(transparent)] +pub struct Wrapper(ExternType); +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +#[repr(transparent)] +pub struct Wrapper2(PhantomData>, ExternType); +pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs b/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs index 5bb8bb024ed51..c23b43dfff706 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-proc_macro_derive.rs @@ -13,7 +13,7 @@ // not descend further into the mod for other occurrences of the same // error. // -// This file sits on its own because the the "weird" occurrences here +// This file sits on its own because the "weird" occurrences here // signal errors, making it incompatible with the "warnings only" // nature of issue-43106-gating-of-builtin-attrs.rs diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed index d16859df79e25..f0aee8a51f18b 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &(1..=2) => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.rs b/src/test/ui/lint/inclusive-range-pattern-syntax.rs index 9d418aec0858f..97bc04faa774b 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.rs +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.rs @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &1...2 => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr index de04fed589b23..b13afdbc023d4 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr @@ -10,3 +10,9 @@ note: lint level defined here LL | #![warn(ellipsis_inclusive_range_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `...` range patterns are deprecated + --> $DIR/inclusive-range-pattern-syntax.rs:25:9 + | +LL | &1...2 => {} + | ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)` + diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr new file mode 100644 index 0000000000000..c308562c0cc76 --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr @@ -0,0 +1,20 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 + | +LL | D("other").next(&_thing1) + | ----------------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs new file mode 100644 index 0000000000000..99eafe0e9d18f --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs @@ -0,0 +1,28 @@ +fn main() { + { + let mut _thing1 = D(Box::new("thing1")); + { + let _thing2 = D("thing2"); + side_effects(); + D("other").next(&_thing1) + } + } + + ; +} + +#[derive(Debug)] +struct D(T); + +impl Drop for D { + fn drop(&mut self) { + println!("dropping {:?})", self); + } +} + +impl D { + fn next(&self, _other: U) -> D { D(_other) } + fn end(&self) { } +} + +fn side_effects() { } diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr new file mode 100644 index 0000000000000..eeba7d6bb445f --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr @@ -0,0 +1,15 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:30 + | +LL | D("other").next(&_thing1) + | ^^^^^^^ borrowed value does not live long enough +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - borrowed value needs to live until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index cd5ce3035c683..6fa67a5d4fa30 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -11,10 +11,10 @@ LL | box 10..=15 => {} | ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)` warning: `...` range patterns are deprecated - --> $DIR/range-inclusive-pattern-precedence.rs:24:11 + --> $DIR/range-inclusive-pattern-precedence.rs:24:9 | LL | &0...9 => {} - | ^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range: `&(0..=9)` | note: lint level defined here --> $DIR/range-inclusive-pattern-precedence.rs:19:9 diff --git a/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs b/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs new file mode 100644 index 0000000000000..af025b9bbbf76 --- /dev/null +++ b/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs @@ -0,0 +1,53 @@ +// run-pass + +// This file checks that `PhantomData` is considered structurally matchable. + +use std::marker::PhantomData; + +fn main() { + let mut count = 0; + + // A type which is not structurally matchable: + struct NotSM; + + // And one that is: + #[derive(PartialEq, Eq)] + struct SM; + + // Check that SM is #[structural_match]: + const CSM: SM = SM; + match SM { + CSM => count += 1, + }; + + // Check that PhantomData is #[structural_match] even if T is not. + const CPD1: PhantomData = PhantomData; + match PhantomData { + CPD1 => count += 1, + }; + + // Check that PhantomData is #[structural_match] when T is. + const CPD2: PhantomData = PhantomData; + match PhantomData { + CPD2 => count += 1, + }; + + // Check that a type which has a PhantomData is `#[structural_match]`. + #[derive(PartialEq, Eq, Default)] + struct Foo { + alpha: PhantomData, + beta: PhantomData, + } + + const CFOO: Foo = Foo { + alpha: PhantomData, + beta: PhantomData, + }; + + match Foo::default() { + CFOO => count += 1, + }; + + // Final count must be 4 now if all + assert_eq!(count, 4); +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f12dd31c402d9..ed2114b653015 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -490,7 +490,7 @@ impl TestProps { } if !self.compile_pass { - // run-pass implies must_compile_sucessfully + // run-pass implies must_compile_successfully self.compile_pass = config.parse_compile_pass(ln) || self.run_pass; }