diff options
32 files changed, 272 insertions, 124 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5406956a528..db7420954a0 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -469,8 +469,8 @@ impl<T: ?Sized> Box<T> { #[inline] #[doc(hidden)] pub fn into_unique(b: Box<T>) -> Unique<T> { + let b = mem::ManuallyDrop::new(b); let mut unique = b.0; - mem::forget(b); // Box is kind-of a library type, but recognized as a "unique pointer" by // Stacked Borrows. This function here corresponds to "reborrowing to // a raw pointer", but there is no actual reborrow here -- so diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index bbeced1751d..36770ee416c 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -4,9 +4,10 @@ use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, FusedIterator, Peekable}; use core::marker::PhantomData; +use core::mem::{self, ManuallyDrop}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, RangeBounds}; -use core::{fmt, mem, ptr}; +use core::{fmt, ptr}; use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; use super::search::{self, SearchResult::*}; @@ -190,9 +191,9 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> { // We can't destructure subtree directly // because BTreeMap implements Drop let (subroot, sublength) = unsafe { + let subtree = ManuallyDrop::new(subtree); let root = ptr::read(&subtree.root); let length = subtree.length; - mem::forget(subtree); (root, length) }; @@ -1515,15 +1516,14 @@ impl<K, V> IntoIterator for BTreeMap<K, V> { type IntoIter = IntoIter<K, V>; fn into_iter(self) -> IntoIter<K, V> { - if self.root.is_none() { - mem::forget(self); + let me = ManuallyDrop::new(self); + if me.root.is_none() { return IntoIter { front: None, back: None, length: 0 }; } - let root1 = unsafe { unwrap_unchecked(ptr::read(&self.root)).into_ref() }; - let root2 = unsafe { unwrap_unchecked(ptr::read(&self.root)).into_ref() }; - let len = self.length; - mem::forget(self); + let root1 = unsafe { unwrap_unchecked(ptr::read(&me.root)).into_ref() }; + let root2 = unsafe { unwrap_unchecked(ptr::read(&me.root)).into_ref() }; + let len = me.length; IntoIter { front: Some(root1.first_leaf_edge()), diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 94532521a90..c17a37c7bae 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -12,7 +12,7 @@ use core::cmp::{self, Ordering}; use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::{once, repeat_with, FromIterator, FusedIterator}; -use core::mem::{self, replace}; +use core::mem::{self, replace, ManuallyDrop}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds, Try}; use core::ptr::{self, NonNull}; @@ -2898,12 +2898,12 @@ impl<T> From<Vec<T>> for VecDeque<T> { /// This avoids reallocating where possible, but the conditions for that are /// strict, and subject to change, and so shouldn't be relied upon unless the /// `Vec<T>` came from `From<VecDeque<T>>` and hasn't been reallocated. - fn from(mut other: Vec<T>) -> Self { + fn from(other: Vec<T>) -> Self { unsafe { + let mut other = ManuallyDrop::new(other); let other_buf = other.as_mut_ptr(); let mut buf = RawVec::from_raw_parts(other_buf, other.capacity()); let len = other.len(); - mem::forget(other); // We need to extend the buf if it's not a power of two, too small // or doesn't have at least one free space @@ -2955,6 +2955,7 @@ impl<T> From<VecDeque<T>> for Vec<T> { other.make_contiguous(); unsafe { + let other = ManuallyDrop::new(other); let buf = other.buf.ptr(); let len = other.len(); let cap = other.cap(); @@ -2962,9 +2963,7 @@ impl<T> From<VecDeque<T>> for Vec<T> { if other.head != 0 { ptr::copy(buf.add(other.tail), buf, len); } - let out = Vec::from_raw_parts(buf, len, cap); - mem::forget(other); - out + Vec::from_raw_parts(buf, len, cap) } } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 2bf40490e78..7ac67870eb7 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -3,7 +3,7 @@ use core::alloc::MemoryBlock; use core::cmp; -use core::mem::{self, MaybeUninit}; +use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::ptr::{NonNull, Unique}; use core::slice; @@ -112,11 +112,10 @@ impl<T> RawVec<T, Global> { } /// Converts a `Box<[T]>` into a `RawVec<T>`. - pub fn from_box(mut slice: Box<[T]>) -> Self { + pub fn from_box(slice: Box<[T]>) -> Self { unsafe { - let result = RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len()); - mem::forget(slice); - result + let mut slice = ManuallyDrop::new(slice); + RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len()) } } } @@ -571,19 +570,21 @@ impl<T> RawVec<T, Global> { /// /// # Safety /// - /// `shrink_to_fit(len)` must be called immediately prior to calling this function. This - /// implies, that `len` must be smaller than or equal to `self.capacity()`. + /// * `len` must be greater than or equal to the most recently requested capacity, and + /// * `len` must be less than or equal to `self.capacity()`. + /// + /// Note, that the requested capacity and `self.capacity()` could differ, as + /// an allocator could overallocate and return a greater memory block than requested. pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> { + // Sanity-check one half of the safety requirement (we cannot check the other half). debug_assert!( len <= self.capacity(), "`len` must be smaller than or equal to `self.capacity()`" ); - // NOTE: not calling `capacity()` here; actually using the real `cap` field! - let slice = slice::from_raw_parts_mut(self.ptr() as *mut MaybeUninit<T>, len); - let output = Box::from_raw(slice); - mem::forget(self); - output + let me = ManuallyDrop::new(self); + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); + Box::from_raw(slice) } } diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 831a42a4b3f..b63d81796f9 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1350,17 +1350,26 @@ fn test_try_reserve_exact() { } #[test] -fn test_stable_push_pop() { +fn test_stable_pointers() { + /// Pull an element from the iterator, then drop it. + /// Useful to cover both the `next` and `drop` paths of an iterator. + fn next_then_drop<I: Iterator>(mut i: I) { + i.next().unwrap(); + drop(i); + } + // Test that, if we reserved enough space, adding and removing elements does not // invalidate references into the vector (such as `v0`). This test also // runs in Miri, which would detect such problems. - let mut v = Vec::with_capacity(10); + let mut v = Vec::with_capacity(128); v.push(13); - // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. - let v0 = unsafe { &*(&v[0] as *const _) }; - + // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = &mut v[0]; + let v0 = unsafe { &mut *(v0 as *mut _) }; // Now do a bunch of things and occasionally use `v0` again to assert it is still valid. + + // Pushing/inserting and popping/removing v.push(1); v.push(2); v.insert(1, 1); @@ -1368,6 +1377,58 @@ fn test_stable_push_pop() { v.remove(1); v.pop().unwrap(); assert_eq!(*v0, 13); + v.push(1); + v.swap_remove(1); + assert_eq!(v.len(), 2); + v.swap_remove(1); // swap_remove the last element + assert_eq!(*v0, 13); + + // Appending + v.append(&mut vec![27, 19]); + assert_eq!(*v0, 13); + + // Extending + v.extend_from_slice(&[1, 2]); + v.extend(&[1, 2]); // `slice::Iter` (with `T: Copy`) specialization + v.extend(vec![2, 3]); // `vec::IntoIter` specialization + v.extend(std::iter::once(3)); // `TrustedLen` specialization + v.extend(std::iter::empty::<i32>()); // `TrustedLen` specialization with empty iterator + v.extend(std::iter::once(3).filter(|_| true)); // base case + v.extend(std::iter::once(&3)); // `cloned` specialization + assert_eq!(*v0, 13); + + // Truncation + v.truncate(2); + assert_eq!(*v0, 13); + + // Resizing + v.resize_with(v.len() + 10, || 42); + assert_eq!(*v0, 13); + v.resize_with(2, || panic!()); + assert_eq!(*v0, 13); + + // No-op reservation + v.reserve(32); + v.reserve_exact(32); + assert_eq!(*v0, 13); + + // Partial draining + v.resize_with(10, || 42); + next_then_drop(v.drain(5..)); + assert_eq!(*v0, 13); + + // Splicing + v.resize_with(10, || 42); + next_then_drop(v.splice(5.., vec![1, 2, 3, 4, 5])); // empty tail after range + assert_eq!(*v0, 13); + next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range + assert_eq!(*v0, 13); + next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact + assert_eq!(*v0, 13); + + // Smoke test that would fire even outside Miri if an actual relocation happened. + *v0 -= 13; + assert_eq!(v[0], 0); } // https://github.com/rust-lang/rust/pull/49496 introduced specialization based on: diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 96a6399d051..a48e48d7da3 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -66,7 +66,7 @@ use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; -use core::mem; +use core::mem::{self, ManuallyDrop}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Index, IndexMut, RangeBounds}; use core::ptr::{self, NonNull}; @@ -392,7 +392,7 @@ impl<T> Vec<T> { /// ``` #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] pub fn into_raw_parts(self) -> (*mut T, usize, usize) { - let mut me = mem::ManuallyDrop::new(self); + let mut me = ManuallyDrop::new(self); (me.as_mut_ptr(), me.len(), me.capacity()) } @@ -678,9 +678,9 @@ impl<T> Vec<T> { pub fn into_boxed_slice(mut self) -> Box<[T]> { unsafe { self.shrink_to_fit(); - let buf = ptr::read(&self.buf); - let len = self.len(); - mem::forget(self); + let me = ManuallyDrop::new(self); + let buf = ptr::read(&me.buf); + let len = me.len(); buf.into_box(len).assume_init() } } @@ -740,7 +740,8 @@ impl<T> Vec<T> { if len > self.len { return; } - let s = self.get_unchecked_mut(len..) as *mut _; + let remaining_len = self.len - len; + let s = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); self.len = len; ptr::drop_in_place(s); } @@ -963,13 +964,15 @@ impl<T> Vec<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { + let len = self.len(); + assert!(index < len); unsafe { // We replace self[index] with the last element. Note that if the - // bounds check on hole succeeds there must be a last element (which + // bounds check above succeeds there must be a last element (which // can be self[index] itself). - let hole: *mut T = &mut self[index]; - let last = ptr::read(self.get_unchecked(self.len - 1)); - self.len -= 1; + let last = ptr::read(self.as_ptr().add(len - 1)); + let hole: *mut T = self.as_mut_ptr().add(index); + self.set_len(len - 1); ptr::replace(hole, last) } } @@ -1200,7 +1203,7 @@ impl<T> Vec<T> { } else { unsafe { self.len -= 1; - Some(ptr::read(self.get_unchecked(self.len()))) + Some(ptr::read(self.as_ptr().add(self.len()))) } } } @@ -1949,16 +1952,16 @@ impl<T> IntoIterator for Vec<T> { /// } /// ``` #[inline] - fn into_iter(mut self) -> IntoIter<T> { + fn into_iter(self) -> IntoIter<T> { unsafe { - let begin = self.as_mut_ptr(); + let mut me = ManuallyDrop::new(self); + let begin = me.as_mut_ptr(); let end = if mem::size_of::<T>() == 0 { - arith_offset(begin as *const i8, self.len() as isize) as *const T + arith_offset(begin as *const i8, me.len() as isize) as *const T } else { - begin.add(self.len()) as *const T + begin.add(me.len()) as *const T }; - let cap = self.buf.capacity(); - mem::forget(self); + let cap = me.buf.capacity(); IntoIter { buf: NonNull::new_unchecked(begin), phantom: PhantomData, @@ -2020,7 +2023,7 @@ where let (lower, _) = iterator.size_hint(); let mut vector = Vec::with_capacity(lower.saturating_add(1)); unsafe { - ptr::write(vector.get_unchecked_mut(0), element); + ptr::write(vector.as_mut_ptr(), element); vector.set_len(1); } vector @@ -2081,9 +2084,8 @@ impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> { // has not been advanced at all. if iterator.buf.as_ptr() as *const _ == iterator.ptr { unsafe { - let vec = Vec::from_raw_parts(iterator.buf.as_ptr(), iterator.len(), iterator.cap); - mem::forget(iterator); - vec + let it = ManuallyDrop::new(iterator); + Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap) } } else { let mut vector = Vec::new(); @@ -2123,8 +2125,9 @@ where self.reserve(slice.len()); unsafe { let len = self.len(); + let dst_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), slice.len()); + dst_slice.copy_from_slice(slice); self.set_len(len + slice.len()); - self.get_unchecked_mut(len..).copy_from_slice(slice); } } } @@ -2145,7 +2148,7 @@ impl<T> Vec<T> { self.reserve(lower.saturating_add(1)); } unsafe { - ptr::write(self.get_unchecked_mut(len), element); + ptr::write(self.as_mut_ptr().add(len), element); // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 0087b92f1f2..c7b5777a16e 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -521,14 +521,16 @@ impl<T, E> Result<T, E> { } } - /// Applies a function to the contained value (if any), - /// or returns the provided default (if not). + /// Applies a function to the contained value (if [`Ok`]), + /// or returns the provided default (if [`Err`]). /// /// Arguments passed to `map_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`map_or_else`], /// which is lazily evaluated. /// /// [`map_or_else`]: #method.map_or_else + /// [`Ok`]: enum.Result.html#variant.Ok + /// [`Err`]: enum.Result.html#variant.Err /// /// # Examples /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 9be52e2dfb0..66aad324618 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -23,6 +23,7 @@ // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. +use crate::borrow::Borrow; use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; @@ -2145,6 +2146,29 @@ impl<T> [T] { } } + /// Fills `self` with elements by cloning `value`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_fill)] + /// + /// let mut buf = vec![0; 10]; + /// buf.fill(1); + /// assert_eq!(buf, vec![1; 10]); + /// ``` + #[unstable(feature = "slice_fill", issue = "70758")] + pub fn fill<V>(&mut self, value: V) + where + V: Borrow<T>, + T: Clone, + { + let value = value.borrow(); + for el in self { + el.clone_from(value) + } + } + /// Copies the elements from `src` into `self`. /// /// The length of `src` must be the same as `self`. diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index e2eae4ac427..7f47b61de3f 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -76,7 +76,7 @@ fn make_mir_scope( } let loc = cx.lookup_debug_loc(scope_data.span.lo()); - let file_metadata = file_metadata(cx, &loc.file.name, debug_context.defining_crate); + let file_metadata = file_metadata(cx, &loc.file, debug_context.defining_crate); let scope_metadata = unsafe { Some(llvm::LLVMRustDIBuilderCreateLexicalBlock( diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 700f25d35bc..82cd8589327 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -41,7 +41,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; -use rustc_span::{self, FileName, SourceFileHash, Span}; +use rustc_span::{self, SourceFile, SourceFileHash, Span}; use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; @@ -761,14 +761,13 @@ fn hex_encode(data: &[u8]) -> String { pub fn file_metadata( cx: &CodegenCx<'ll, '_>, - file_name: &FileName, + source_file: &SourceFile, defining_crate: CrateNum, ) -> &'ll DIFile { - debug!("file_metadata: file_name: {}, defining_crate: {}", file_name, defining_crate); + debug!("file_metadata: file_name: {}, defining_crate: {}", source_file.name, defining_crate); - let source_file = cx.sess().source_map().get_source_file(file_name); - let hash = source_file.as_ref().map(|f| &f.src_hash); - let file_name = Some(file_name.to_string()); + let hash = Some(&source_file.src_hash); + let file_name = Some(source_file.name.to_string()); let directory = if defining_crate == LOCAL_CRATE { Some(cx.sess().working_dir.0.to_string_lossy().to_string()) } else { @@ -2331,7 +2330,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global let (file_metadata, line_number) = if !span.is_dummy() { let loc = cx.lookup_debug_loc(span.lo()); - (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line) + (file_metadata(cx, &loc.file, LOCAL_CRATE), loc.line) } else { (unknown_file_metadata(cx), None) }; @@ -2440,6 +2439,6 @@ pub fn extend_scope_to_file( file: &rustc_span::SourceFile, defining_crate: CrateNum, ) -> &'ll DILexicalBlock { - let file_metadata = file_metadata(cx, &file.name, defining_crate); + let file_metadata = file_metadata(cx, &file, defining_crate); unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) } } diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index f04ac586504..37f502c56a6 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -249,7 +249,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let def_id = instance.def_id(); let containing_scope = get_containing_scope(self, instance); let loc = self.lookup_debug_loc(span.lo()); - let file_metadata = file_metadata(self, &loc.file.name, def_id.krate); + let file_metadata = file_metadata(self, &loc.file, def_id.krate); let function_type_metadata = unsafe { let fn_signature = get_function_signature(self, fn_abi); @@ -536,7 +536,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { span: Span, ) -> &'ll DIVariable { let loc = self.lookup_debug_loc(span.lo()); - let file_metadata = file_metadata(self, &loc.file.name, dbg_context.defining_crate); + let file_metadata = file_metadata(self, &loc.file, dbg_context.defining_crate); let type_metadata = type_metadata(self, variable_type, span); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index ccbce01d6c1..acf8f1adbc2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -136,7 +136,6 @@ pub fn diagnostics_registry() -> Registry { } // Parse args and run the compiler. This is the primary entry point for rustc. -// See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. pub fn run_compiler( at_args: &[String], diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index e868b7e36aa..5fb800972c7 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -768,7 +768,7 @@ fn may_begin_with(token: &Token, name: Name) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { match *nt { - token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) => false, + token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => false, _ => true, } } diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index 88c3d0ec56f..913c67d045e 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -58,5 +58,4 @@ pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); - rustc_middle::ty::RESOLVE_INSTANCE.swap(&(rustc_ty::instance::resolve_instance as _)); } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 2ffbbfb1762..c26c043994f 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1257,5 +1257,9 @@ rustc_queries! { eval_always desc { "looking up enabled feature gates" } } + + query resolve_instance(key: (ty::ParamEnv<'tcx>, DefId, SubstsRef<'tcx>)) -> Option<ty::Instance<'tcx>> { + desc { "resolving instance `{:?}` `{:?}` with {:?}", key.1, key.2, key.0 } + } } } diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 5d47a6e13f4..cf0222370f2 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -1,7 +1,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::AtomicRef; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::DropInPlaceFnLangItem; @@ -289,7 +288,9 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Option<Instance<'tcx>> { - (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs) + // All regions in the result of this query are erased, so it's + // fine to erase all of the input regions. + tcx.resolve_instance((tcx.erase_regions(¶m_env), def_id, tcx.erase_regions(&substs))) } pub fn resolve_for_fn_ptr( @@ -440,21 +441,3 @@ fn needs_fn_once_adapter_shim( (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()), } } - -fn resolve_instance_default( - _tcx: TyCtxt<'tcx>, - _param_env: ty::ParamEnv<'tcx>, - _def_id: DefId, - _substs: SubstsRef<'tcx>, -) -> Option<Instance<'tcx>> { - unimplemented!() -} - -pub static RESOLVE_INSTANCE: AtomicRef< - for<'tcx> fn( - TyCtxt<'tcx>, - ty::ParamEnv<'tcx>, - DefId, - SubstsRef<'tcx>, - ) -> Option<Instance<'tcx>>, -> = AtomicRef::new(&(resolve_instance_default as _)); diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 520793c69fd..5740f8cc091 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -285,11 +285,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); - let mut optimize = !repr.inhibit_struct_field_reordering_opt(); - if let StructKind::Prefixed(_, align) = kind { - optimize &= align.bytes() == 1; - } - + let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; @@ -307,6 +303,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }); } StructKind::Prefixed(..) => { + // Sort in ascending alignment so that the layout stay optimal + // regardless of the prefix optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); } } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 9b182333907..0ebd55a6c02 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -81,7 +81,6 @@ pub use self::context::{ CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckTables, }; -pub use self::instance::RESOLVE_INSTANCE; pub use self::instance::{Instance, InstanceDef}; pub use self::trait_def::TraitDef; diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index a261e484a85..438e7ed4331 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -296,3 +296,14 @@ impl Key for (Symbol, u32, u32) { DUMMY_SP } } + +impl<'tcx> Key for (ty::ParamEnv<'tcx>, DefId, SubstsRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.1.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.1) + } +} diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 10d3101ebb8..0b182d42287 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,11 +14,11 @@ use rustc_middle::mir::interpret::{ sign_extend, truncate, AllocId, FrameInfo, GlobalId, InterpResult, Pointer, Scalar, }; use rustc_middle::ty::layout::{self, TyAndLayout}; -use rustc_middle::ty::query::TyCtxtAt; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable, +}; use rustc_span::source_map::DUMMY_SP; -use rustc_target::abi::{Abi, Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; +use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use super::{ Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, @@ -213,6 +213,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( + tcx: TyCtxt<'tcx>, src: TyAndLayout<'tcx>, dest: TyAndLayout<'tcx>, ) -> bool { @@ -220,23 +221,42 @@ pub(super) fn mir_assign_valid_types<'tcx>( // Equal types, all is good. return true; } - // Type-changing assignments can happen for (at least) two reasons: - // - `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment. - // - Subtyping is used. While all normal lifetimes are erased, higher-ranked lifetime - // bounds are still around and can lead to type differences. - // There is no good way to check the latter, so we compare layouts instead -- but only - // for values with `Scalar`/`ScalarPair` abi. - // FIXME: Do something more accurate, type-based. - match &src.abi { - Abi::Scalar(..) | Abi::ScalarPair(..) => src.layout == dest.layout, - _ => false, + if src.layout != dest.layout { + // Layout differs, definitely not equal. + // We do this here because Miri would *do the wrong thing* if we allowed layout-changing + // assignments. + return false; } + + // Type-changing assignments can happen for (at least) two reasons: + // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment. + // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types + // with their late-bound lifetimes are still around and can lead to type differences. + // Normalize both of them away. + let normalize = |ty: Ty<'tcx>| { + ty.fold_with(&mut BottomUpFolder { + tcx, + // Normalize all references to immutable. + ty_op: |ty| match ty.kind { + ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee), + _ => ty, + }, + // We just erase all late-bound lifetimes, but this is not fully correct (FIXME): + // lifetimes in invariant positions could matter (e.g. through associated types). + // We rely on the fact that layout was confirmed to be equal above. + lt_op: |_| tcx.lifetimes.re_erased, + // Leave consts unchanged. + ct_op: |ct| ct, + }) + }; + normalize(src.ty) == normalize(dest.ty) } /// Use the already known layout if given (but sanity check in debug mode), /// or compute the layout. #[cfg_attr(not(debug_assertions), inline(always))] pub(super) fn from_known_layout<'tcx>( + tcx: TyCtxt<'tcx>, known_layout: Option<TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -246,7 +266,7 @@ pub(super) fn from_known_layout<'tcx>( if cfg!(debug_assertions) { let check_layout = compute()?; assert!( - mir_assign_valid_types(check_layout, known_layout), + mir_assign_valid_types(tcx, check_layout, known_layout), "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}", known_layout.ty, check_layout.ty, @@ -424,7 +444,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // have to support that case (mostly by skipping all caching). match frame.locals.get(local).and_then(|state| state.layout.get()) { None => { - let layout = from_known_layout(layout, || { + let layout = from_known_layout(self.tcx.tcx, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 12595e4e4d9..03614b2803f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -529,7 +529,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Value(val_val) => val_val, }; // Other cases need layout. - let layout = from_known_layout(layout, || self.layout_of(val.ty))?; + let layout = from_known_layout(self.tcx.tcx, layout, || self.layout_of(val.ty))?; let op = match val_val { ConstValue::ByRef { alloc, offset } => { let id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index ec299cdd213..716c7c7d933 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -868,7 +868,7 @@ where // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. assert!( - mir_assign_valid_types(src.layout, dest.layout), + mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout), "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", src.layout.ty, dest.layout.ty, @@ -922,7 +922,7 @@ where src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - if mir_assign_valid_types(src.layout, dest.layout) { + if mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { // Fast path: Just use normal `copy_op` return self.copy_op(src, dest); } diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 8ad743d2b8b..6ebe5b80370 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -75,7 +75,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Drop { location, target, unwind } => { - // FIXME(CTFE): forbid drop in const eval let place = self.eval_place(location)?; let ty = place.layout.ty; trace!("TerminatorKind::drop: {:?}, type {}", location, ty); diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs index ee29d672b46..3f9dad689fd 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/src/librustc_target/spec/hermit_base.rs @@ -14,7 +14,6 @@ pub fn opts() -> TargetOptions { has_elf_tls: true, linker_is_gnu: true, pre_link_args, - no_default_libraries: true, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, relocation_model: "static".to_string(), diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/src/librustc_target/spec/hermit_kernel_base.rs index 44d3ee67181..650219c21ac 100644 --- a/src/librustc_target/spec/hermit_kernel_base.rs +++ b/src/librustc_target/spec/hermit_kernel_base.rs @@ -15,7 +15,6 @@ pub fn opts() -> TargetOptions { has_elf_tls: true, linker_is_gnu: true, pre_link_args, - no_default_libraries: true, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, relocation_model: "static".to_string(), diff --git a/src/librustc_target/spec/windows_base.rs b/src/librustc_target/spec/windows_base.rs index 5f59ca8a5a3..34fcdf251b8 100644 --- a/src/librustc_target/spec/windows_base.rs +++ b/src/librustc_target/spec/windows_base.rs @@ -77,7 +77,6 @@ pub fn opts() -> TargetOptions { exe_suffix: ".exe".to_string(), staticlib_prefix: String::new(), staticlib_suffix: ".lib".to_string(), - no_default_libraries: true, target_family: Some("windows".to_string()), is_like_windows: true, allows_weak_linkage: false, diff --git a/src/librustc_target/spec/windows_uwp_base.rs b/src/librustc_target/spec/windows_uwp_base.rs index 3f7eb442bbc..f19bd10dc0b 100644 --- a/src/librustc_target/spec/windows_uwp_base.rs +++ b/src/librustc_target/spec/windows_uwp_base.rs @@ -43,7 +43,6 @@ pub fn opts() -> TargetOptions { exe_suffix: ".exe".to_string(), staticlib_prefix: "lib".to_string(), staticlib_suffix: ".a".to_string(), - no_default_libraries: true, target_family: Some("windows".to_string()), is_like_windows: true, allows_weak_linkage: false, diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 677e373f2f4..955e2e36159 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -11,9 +11,7 @@ use log::debug; pub fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, + (param_env, def_id, substs): (ty::ParamEnv<'tcx>, DefId, SubstsRef<'tcx>), ) -> Option<Instance<'tcx>> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { @@ -199,3 +197,7 @@ fn resolve_associated_item<'tcx>( traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None, } } + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { resolve_instance, ..*providers }; +} diff --git a/src/librustc_ty/lib.rs b/src/librustc_ty/lib.rs index 04909b8b0c1..75e62e79640 100644 --- a/src/librustc_ty/lib.rs +++ b/src/librustc_ty/lib.rs @@ -25,4 +25,5 @@ pub fn provide(providers: &mut Providers<'_>) { common_traits::provide(providers); needs_drop::provide(providers); ty::provide(providers); + instance::provide(providers); } diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs new file mode 100644 index 00000000000..59d46ea66c9 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(const_fn)] + +const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) { + x +} + +pub const TEST: (fn(&'static ()), String) = nested((|_x| (), String::new())); + +fn main() {} diff --git a/src/test/ui/macros/issue-70446.rs b/src/test/ui/macros/issue-70446.rs new file mode 100644 index 00000000000..407094d55ff --- /dev/null +++ b/src/test/ui/macros/issue-70446.rs @@ -0,0 +1,13 @@ +// check-pass + +macro_rules! foo { + ($(: $p:path)? $(: $l:lifetime)? ) => { bar! {$(: $p)? $(: $l)? } }; +} + +macro_rules! bar { + ($(: $p:path)? $(: $l:lifetime)? ) => {}; +} + +foo! {: 'a } + +fn main() {} diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs index 1d332cc3bf7..6a3f3c98f12 100644 --- a/src/test/ui/type-sizes.rs +++ b/src/test/ui/type-sizes.rs @@ -37,6 +37,29 @@ enum ReorderedEnum { B(u8, u16, u8), } +enum ReorderedEnum2 { + A(u8, u32, u8), + B(u16, u8, u16, u8), + + // 0x100 niche variants. + _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F, + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F, + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F, + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F, + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F, + _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F, + _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F, + _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F, + _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F, + _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F, + _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF, + _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF, + _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF, + _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF, + _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF, + _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF, +} + enum EnumEmpty {} enum EnumSingle1 { @@ -104,6 +127,8 @@ pub fn main() { assert_eq!(size_of::<e3>(), 4 as usize); assert_eq!(size_of::<ReorderedStruct>(), 4); assert_eq!(size_of::<ReorderedEnum>(), 6); + assert_eq!(size_of::<ReorderedEnum2>(), 8); + assert_eq!(size_of::<EnumEmpty>(), 0); assert_eq!(size_of::<EnumSingle1>(), 0); |
