diff --git a/Cargo.lock b/Cargo.lock index a912eee97dbf2..1fe03a06c7974 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,9 +1505,9 @@ dependencies = [ [[package]] name = "gsgdt" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60" +checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825" dependencies = [ "serde", ] diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3e7371179cc72..01f7868df3492 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -160,17 +160,17 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // the values should match the ones in the DWARF standard anyway. let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; - let mut addr_ops = SmallVec::<[_; 8]>::new(); + let mut addr_ops = SmallVec::<[u64; 8]>::new(); if direct_offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(direct_offset.bytes() as i64); + addr_ops.push(direct_offset.bytes() as u64); } for &offset in indirect_offsets { addr_ops.push(op_deref()); if offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(offset.bytes() as i64); + addr_ops.push(offset.bytes() as u64); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6450b7490bd2b..f2782f84f557b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2108,7 +2108,7 @@ extern "C" { Builder: &DIBuilder<'a>, Val: &'a Value, VarInfo: &'a DIVariable, - AddrOps: *const i64, + AddrOps: *const u64, AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, @@ -2199,8 +2199,8 @@ extern "C" { Scope: &'a DIScope, InlinedAt: Option<&'a DILocation>, ) -> &'a DILocation; - pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; - pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64; + pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; + pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 7c97143e80780..79c24f0f17280 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -6,8 +6,8 @@ use std::path::Path; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ - elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags, - SectionKind, SymbolFlags, SymbolKind, SymbolScope, + elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; use snap::write::FrameEncoder; @@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec { ); match file.format() { BinaryFormat::Coff => { - const IMAGE_SCN_LNK_REMOVE: u32 = 0; file.section_mut(section).flags = - SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE }; + SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE }; } BinaryFormat::Elf => { - const SHF_EXCLUDE: u64 = 0x80000000; - file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE }; + file.section_mut(section).flags = + SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 }; } _ => {} }; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 025a0ee376e3e..2a0f4fdc77412 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -979,11 +979,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, + uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(V), unwrap(VarInfo), - Builder->createExpression(llvm::ArrayRef(AddrOps, AddrOpsCount)), + Builder->createExpression(llvm::ArrayRef(AddrOps, AddrOpsCount)), DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd))); } @@ -1057,11 +1057,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, return wrap(Loc); } -extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } -extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f8d3fb6c48de7..a9db8469384ed 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,7 @@ doctest = false rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" either = "1.5.0" -gsgdt = "0.1.3" +gsgdt = "0.1.2" tracing = "0.1" rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index 44d0ce935df7f..770b52a4d4b0f 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); stmts.push(terminator_head); - Node::from_list(stmts, label, title, style) + Node::new(stmts, label, title, style) } // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 66ef92558d8b5..d075658f51a3e 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -323,17 +323,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] +#[rustc_const_unstable(feature = "const_box", issue = "92521")] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +pub(crate) const unsafe fn box_free( + ptr: Unique, + alloc: A, +) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.deallocate(ptr.cast().into(), layout) + alloc.deallocate(From::from(ptr.cast()), layout) } } @@ -361,13 +365,22 @@ extern "Rust" { /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] +#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] #[rustc_allocator_nounwind] #[cold] -pub fn handle_alloc_error(layout: Layout) -> ! { - unsafe { - __rust_alloc_error_handler(layout.size(), layout.align()); +pub const fn handle_alloc_error(layout: Layout) -> ! { + const fn ct_error(_: Layout) -> ! { + panic!("allocation failed"); } + + fn rt_error(layout: Layout) -> ! { + unsafe { + __rust_alloc_error_handler(layout.size(), layout.align()); + } + } + + unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } } // For alloc test `std::alloc::handle_alloc_error` can be used directly. diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ab41f5646e5e5..aa7344ba405a9 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -346,9 +346,13 @@ impl Box { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline] - pub fn new_in(x: T, alloc: A) -> Self { + pub const fn new_in(x: T, alloc: A) -> Self + where + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::new_uninit_in(alloc); unsafe { boxed.as_mut_ptr().write(x); @@ -372,8 +376,13 @@ impl Box { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn try_new_in(x: T, alloc: A) -> Result { + pub const fn try_new_in(x: T, alloc: A) -> Result + where + T: ~const Drop, + A: ~const Allocator + ~const Drop, + { let mut boxed = Self::try_new_uninit_in(alloc)?; unsafe { boxed.as_mut_ptr().write(x); @@ -402,10 +411,14 @@ impl Box { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] #[must_use] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn new_uninit_in(alloc: A) -> Box, A> { + pub const fn new_uninit_in(alloc: A) -> Box, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -439,7 +452,11 @@ impl Box { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); let ptr = alloc.allocate(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -466,10 +483,14 @@ impl Box { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[cfg(not(no_global_oom_handling))] // #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] - pub fn new_zeroed_in(alloc: A) -> Box, A> { + pub const fn new_zeroed_in(alloc: A) -> Box, A> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -503,7 +524,11 @@ impl Box { /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> + where + A: ~const Allocator + ~const Drop, + { let layout = Layout::new::>(); let ptr = alloc.allocate_zeroed(layout)?.cast(); unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } @@ -513,20 +538,22 @@ impl Box { /// `x` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[must_use] #[inline(always)] - pub fn pin_in(x: T, alloc: A) -> Pin + pub const fn pin_in(x: T, alloc: A) -> Pin where - A: 'static, + A: 'static + ~const Allocator + ~const Drop, { - Self::new_in(x, alloc).into() + Self::into_pin(Self::new_in(x, alloc)) } /// Converts a `Box` into a `Box<[T]>` /// /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] - pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> { let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } @@ -543,8 +570,12 @@ impl Box { /// assert_eq!(Box::into_inner(c), 5); /// ``` #[unstable(feature = "box_into_inner", issue = "80437")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn into_inner(boxed: Self) -> T { + pub const fn into_inner(boxed: Self) -> T + where + Self: ~const Drop, + { *boxed } } @@ -758,8 +789,9 @@ impl Box, A> { /// assert_eq!(*five, 5) /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub unsafe fn assume_init(self) -> Box { + pub const unsafe fn assume_init(self) -> Box { let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } @@ -792,8 +824,9 @@ impl Box, A> { /// } /// ``` #[unstable(feature = "new_uninit", issue = "63291")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn write(mut boxed: Self, value: T) -> Box { + pub const fn write(mut boxed: Self, value: T) -> Box { unsafe { (*boxed).write(value); boxed.assume_init() @@ -938,8 +971,9 @@ impl Box { /// [memory layout]: self#memory-layout /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { + pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self { Box(unsafe { Unique::new_unchecked(raw) }, alloc) } @@ -1035,8 +1069,9 @@ impl Box { /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { + pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -1046,9 +1081,10 @@ impl Box { issue = "none", reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead" )] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] #[doc(hidden)] - pub fn into_unique(b: Self) -> (Unique, A) { + pub const fn into_unique(b: Self) -> (Unique, A) { // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a // raw pointer for the type system. Turning it directly into a raw pointer would not be // recognized as "releasing" the unique pointer to permit aliased raw accesses, @@ -1064,8 +1100,9 @@ impl Box { /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn allocator(b: &Self) -> &A { + pub const fn allocator(b: &Self) -> &A { &b.1 } @@ -1105,8 +1142,9 @@ impl Box { /// assert_eq!(*static_ref, [4, 2, 3]); /// ``` #[stable(feature = "box_leak", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] - pub fn leak<'a>(b: Self) -> &'a mut T + pub const fn leak<'a>(b: Self) -> &'a mut T where A: 'a, { @@ -1119,7 +1157,8 @@ impl Box { /// /// This is also available via [`From`]. #[unstable(feature = "box_into_pin", issue = "62370")] - pub fn into_pin(boxed: Self) -> Pin + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + pub const fn into_pin(boxed: Self) -> Pin where A: 'static, { @@ -1131,7 +1170,8 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -1341,7 +1381,8 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -impl From> for Pin> +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl const From> for Pin> where A: 'static, { @@ -1720,7 +1761,8 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Box { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl const Deref for Box { type Target = T; fn deref(&self) -> &T { @@ -1729,7 +1771,8 @@ impl Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for Box { +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl const DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self } @@ -1908,7 +1951,8 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Box where A: 'static {} +#[rustc_const_unstable(feature = "const_box", issue = "92521")] +impl const Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] impl + Unpin, R, A: Allocator> Generator for Box diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 600862c4224a1..7e663fab16af5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,9 +96,20 @@ #![feature(array_windows)] #![feature(async_stream)] #![feature(coerce_unsized)] +#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] +#![feature(const_box)] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] #![feature(const_cow_is_borrowed)] +#![feature(const_convert)] +#![feature(const_size_of_val)] +#![feature(const_align_of_val)] +#![feature(const_ptr_read)] +#![feature(const_maybe_uninit_write)] +#![feature(const_maybe_uninit_as_mut_ptr)] +#![feature(const_refs_to_cell)] #![feature(core_intrinsics)] +#![feature(const_eval_select)] +#![feature(const_pin)] #![feature(dispatch_from_dyn)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -134,8 +145,13 @@ #![feature(box_syntax)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] +#![feature(const_deref)] #![feature(const_fn_trait_bound)] +#![feature(const_mut_refs)] +#![feature(const_ptr_write)] +#![feature(const_precise_live_drops)] #![feature(const_trait_impl)] +#![feature(const_try)] #![cfg_attr(bootstrap, feature(destructuring_assignment))] #![feature(dropck_eyepatch)] #![feature(exclusive_range_pattern)] diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index bfe66b2687ef4..0d7acfed8c6a1 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -1,6 +1,7 @@ -use std::cell::Cell; -use std::mem::MaybeUninit; -use std::ptr::NonNull; +use core::alloc::{AllocError, Allocator, Layout}; +use core::cell::Cell; +use core::mem::MaybeUninit; +use core::ptr::NonNull; #[test] fn uninitialized_zero_size_box() { @@ -57,3 +58,110 @@ fn box_deref_lval() { x.set(1000); assert_eq!(x.get(), 1000); } + +pub struct ConstAllocator; + +unsafe impl const Allocator for ConstAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + _ => unsafe { + let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) + }, + } + } + + unsafe fn deallocate(&self, _ptr: NonNull, layout: Layout) { + match layout.size() { + 0 => { /* do nothing */ } + _ => { /* do nothing too */ } + } + } + + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; + if layout.size() > 0 { + unsafe { + ptr.as_mut_ptr().write_bytes(0, layout.size()); + } + } + Ok(ptr) + } + + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + let new_ptr = self.grow(ptr, old_layout, new_layout)?; + if new_layout.size() > 0 { + let old_size = old_layout.size(); + let new_size = new_layout.size(); + let raw_ptr = new_ptr.as_mut_ptr(); + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } + Ok(new_ptr) + } + + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + + let new_ptr = self.allocate(new_layout)?; + if new_layout.size() > 0 { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + + fn by_ref(&self) -> &Self + where + Self: Sized, + { + self + } +} + +#[test] +fn const_box() { + const VALUE: u32 = { + let mut boxed = Box::new_in(1u32, ConstAllocator); + assert!(*boxed == 1); + + *boxed = 42; + assert!(*boxed == 42); + + *boxed + }; + + assert!(VALUE == 42); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 68e48348b076e..eec24a5c3f7e6 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,8 +1,19 @@ #![feature(allocator_api)] +#![feature(alloc_layout_extra)] #![feature(assert_matches)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] +#![feature(const_box)] +#![feature(const_convert)] #![feature(const_cow_is_borrowed)] +#![feature(const_heap)] +#![feature(const_intrinsic_copy)] +#![feature(const_mut_refs)] +#![feature(const_nonnull_slice_from_raw_parts)] +#![feature(const_ptr_offset)] +#![feature(const_ptr_write)] +#![feature(const_try)] +#![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] @@ -26,6 +37,7 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] +#![feature(nonnull_slice_from_raw_parts)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index e84dfbce4a754..5ad570427978e 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -268,7 +268,7 @@ impl Command { } else { None }; - let program = resolve_exe(&self.program, child_paths)?; + let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?; let mut cmd_str = make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?; cmd_str.push(0); // add null terminator @@ -362,7 +362,11 @@ impl fmt::Debug for Command { // Therefore this functions first assumes `.exe` was intended. // It falls back to the plain file name if a full path is given and the extension is omitted // or if only a file name is given and it already contains an extension. -fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Result { +fn resolve_exe<'a>( + exe_path: &'a OsStr, + parent_paths: impl FnOnce() -> Option, + child_paths: Option<&OsStr>, +) -> io::Result { // Early return if there is no filename. if exe_path.is_empty() || path::has_trailing_slash(exe_path) { return Err(io::Error::new_const( @@ -406,7 +410,7 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu let has_extension = exe_path.bytes().contains(&b'.'); // Search the directories given by `search_paths`. - let result = search_paths(child_paths, |mut path| { + let result = search_paths(parent_paths, child_paths, |mut path| { path.push(&exe_path); if !has_extension { path.set_extension(EXE_EXTENSION); @@ -423,15 +427,20 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu // Calls `f` for every path that should be used to find an executable. // Returns once `f` returns the path to an executable or all paths have been searched. -fn search_paths(child_paths: Option<&OsStr>, mut f: F) -> Option +fn search_paths( + parent_paths: Paths, + child_paths: Option<&OsStr>, + mut exists: Exists, +) -> Option where - F: FnMut(PathBuf) -> Option, + Paths: FnOnce() -> Option, + Exists: FnMut(PathBuf) -> Option, { // 1. Child paths // This is for consistency with Rust's historic behaviour. if let Some(paths) = child_paths { for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) { - if let Some(path) = f(path) { + if let Some(path) = exists(path) { return Some(path); } } @@ -440,7 +449,7 @@ where // 2. Application path if let Ok(mut app_path) = env::current_exe() { app_path.pop(); - if let Some(path) = f(app_path) { + if let Some(path) = exists(app_path) { return Some(path); } } @@ -450,7 +459,7 @@ where unsafe { if let Ok(Some(path)) = super::fill_utf16_buf( |buf, size| c::GetSystemDirectoryW(buf, size), - |buf| f(PathBuf::from(OsString::from_wide(buf))), + |buf| exists(PathBuf::from(OsString::from_wide(buf))), ) { return Some(path); } @@ -458,7 +467,7 @@ where { if let Ok(Some(path)) = super::fill_utf16_buf( |buf, size| c::GetWindowsDirectoryW(buf, size), - |buf| f(PathBuf::from(OsString::from_wide(buf))), + |buf| exists(PathBuf::from(OsString::from_wide(buf))), ) { return Some(path); } @@ -466,9 +475,9 @@ where } // 5. Parent paths - if let Some(parent_paths) = env::var_os("PATH") { + if let Some(parent_paths) = parent_paths() { for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) { - if let Some(path) = f(path) { + if let Some(path) = exists(path) { return Some(path); } } diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index 6159a679c0e69..f1221767af30e 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -136,51 +136,46 @@ fn windows_exe_resolver() { use super::resolve_exe; use crate::io; + let env_paths = || env::var_os("PATH"); + // Test a full path, with and without the `exe` extension. let mut current_exe = env::current_exe().unwrap(); - assert!(resolve_exe(current_exe.as_ref(), None).is_ok()); + assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok()); current_exe.set_extension(""); - assert!(resolve_exe(current_exe.as_ref(), None).is_ok()); + assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok()); // Test lone file names. - assert!(resolve_exe(OsStr::new("cmd"), None).is_ok()); - assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok()); - assert!(resolve_exe(OsStr::new("cmd.EXE"), None).is_ok()); - assert!(resolve_exe(OsStr::new("fc"), None).is_ok()); + assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok()); + assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok()); + assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok()); + assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok()); // Invalid file names should return InvalidInput. - assert_eq!(resolve_exe(OsStr::new(""), None).unwrap_err().kind(), io::ErrorKind::InvalidInput); assert_eq!( - resolve_exe(OsStr::new("\0"), None).unwrap_err().kind(), + resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(), + io::ErrorKind::InvalidInput + ); + assert_eq!( + resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(), io::ErrorKind::InvalidInput ); // Trailing slash, therefore there's no file name component. assert_eq!( - resolve_exe(OsStr::new(r"C:\Path\to\"), None).unwrap_err().kind(), + resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(), io::ErrorKind::InvalidInput ); - /* FIXME: fix and re-enable these tests before making changes to the resolver. - /* Some of the following tests may need to be changed if you are deliberately changing the behaviour of `resolve_exe`. */ - let paths = env::var_os("PATH").unwrap(); - env::set_var("PATH", ""); - - assert_eq!(resolve_exe(OsStr::new("rustc"), None).unwrap_err().kind(), io::ErrorKind::NotFound); - - let child_paths = Some(paths.as_os_str()); - assert!(resolve_exe(OsStr::new("rustc"), child_paths).is_ok()); + let empty_paths = || None; // The resolver looks in system directories even when `PATH` is empty. - assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok()); + assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok()); // The application's directory is also searched. let current_exe = env::current_exe().unwrap(); - assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), None).is_ok()); - - */ + assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok()); } diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index eb0925b3fda7d..684b8e3155e84 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -15,7 +15,9 @@ use core::str::utf8_char_width; // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. pub struct Stdin { surrogate: u16, + incomplete_utf8: IncompleteUtf8, } + pub struct Stdout { incomplete_utf8: IncompleteUtf8, } @@ -29,6 +31,25 @@ struct IncompleteUtf8 { len: u8, } +impl IncompleteUtf8 { + // Implemented for use in Stdin::read. + fn read(&mut self, buf: &mut [u8]) -> usize { + // Write to buffer until the buffer is full or we run out of bytes. + let to_write = cmp::min(buf.len(), self.len as usize); + buf[..to_write].copy_from_slice(&self.bytes[..to_write]); + + // Rotate the remaining bytes if not enough remaining space in buffer. + if usize::from(self.len) > buf.len() { + self.bytes.copy_within(to_write.., 0); + self.len -= to_write as u8; + } else { + self.len = 0; + } + + to_write + } +} + // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see // #13304 for details). // @@ -205,7 +226,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result { impl Stdin { pub const fn new() -> Stdin { - Stdin { surrogate: 0 } + Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() } } } @@ -221,24 +242,39 @@ impl io::Read for Stdin { } } - if buf.len() == 0 { - return Ok(0); - } else if buf.len() < 4 { - return Err(io::Error::new_const( - io::ErrorKind::InvalidInput, - &"Windows stdin in console mode does not support a buffer too small to \ - guarantee holding one arbitrary UTF-8 character (4 bytes)", - )); + // If there are bytes in the incomplete utf-8, start with those. + // (No-op if there is nothing in the buffer.) + let mut bytes_copied = self.incomplete_utf8.read(buf); + + if bytes_copied == buf.len() { + return Ok(bytes_copied); + } else if buf.len() - bytes_copied < 4 { + // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. + let mut utf16_buf = [0u16; 1]; + // Read one u16 character. + let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; + // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. + let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?; + + // Read in the bytes from incomplete_utf8 until the buffer is full. + self.incomplete_utf8.len = read_bytes as u8; + // No-op if no bytes. + bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); + Ok(bytes_copied) + } else { + let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; + // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So + // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets + // lost. + let amount = cmp::min(buf.len() / 3, utf16_buf.len()); + let read = + read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; + + match utf16_to_utf8(&utf16_buf[..read], buf) { + Ok(value) => return Ok(bytes_copied + value), + Err(e) => return Err(e), + } } - - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; - // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So - // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets - // lost. - let amount = cmp::min(buf.len() / 3, utf16_buf.len()); - let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - utf16_to_utf8(&utf16_buf[..read], buf) } }