From aa6795e2d4cdae6af2ea854744c3bec2eb30d16e Mon Sep 17 00:00:00 2001 From: woppopo Date: Sat, 25 Dec 2021 22:35:11 +0900 Subject: [PATCH 01/14] Add `intrinsics::const_deallocate` --- .../src/const_eval/machine.rs | 17 +++++++++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/intrinsic.rs | 5 ++++ library/core/src/intrinsics.rs | 6 ++++ .../const-eval/heap/dealloc_intrinsic.rs | 12 ++++++++ .../heap/dealloc_intrinsic_dangling.rs | 22 ++++++++++++++ .../heap/dealloc_intrinsic_dangling.stderr | 15 ++++++++++ .../heap/dealloc_intrinsic_duplicate.rs | 13 +++++++++ .../heap/dealloc_intrinsic_duplicate.stderr | 9 ++++++ .../dealloc_intrinsic_incorrect_layout.rs | 29 +++++++++++++++++++ .../dealloc_intrinsic_incorrect_layout.stderr | 27 +++++++++++++++++ 11 files changed, 156 insertions(+) create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 30e9cbe440354..62eaf3333404e 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -347,6 +347,23 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, )?; ecx.write_pointer(ptr, dest)?; } + sym::const_deallocate => { + let ptr = ecx.read_pointer(&args[0])?; + let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?; + + let size = Size::from_bytes(size); + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + ecx.memory.deallocate( + ptr, + Some((size, align)), + interpret::MemoryKind::Machine(MemoryKind::Heap), + )?; + } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9870c90f2ec94..c87bb1d57471a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -460,6 +460,7 @@ symbols! { const_async_blocks, const_compare_raw_pointers, const_constructor, + const_deallocate, const_eval_limit, const_eval_select, const_eval_select_ct, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 4c612ed5be51a..74f6f50d41289 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -297,6 +297,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::const_allocate => { (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) } + sym::const_deallocate => ( + 0, + vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize], + tcx.mk_unit(), + ), sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 9781dc320edde..10b5e06fc505c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1918,6 +1918,12 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; + /// Deallocate a memory which allocated by `intrinsics::const_allocate` at compile time. + /// Should not be called at runtime. + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[cfg(not(bootstrap))] + pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); + /// Determines whether the raw bytes of the two values are equal. /// /// This is particularly handy for arrays, since it allows things like just diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs new file mode 100644 index 0000000000000..b7c2b75264429 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -0,0 +1,12 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs new file mode 100644 index 0000000000000..b6d89a58dce7b --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -0,0 +1,22 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_mut_refs)] + +use std::intrinsics; + +const _X: &'static u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + &*ptr + //~^ error: evaluation of constant value failed +}; + +const _Y: u8 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let reference = &*ptr; + intrinsics::const_deallocate(ptr, 4, 4); + *reference + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr new file mode 100644 index 0000000000000..4eb1c42e1f767 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:10:5 + | +LL | &*ptr + | ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_dangling.rs:18:5 + | +LL | *reference + | ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs new file mode 100644 index 0000000000000..4010b476990dc --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs @@ -0,0 +1,13 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + intrinsics::const_deallocate(ptr, 4, 4); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr new file mode 100644 index 0000000000000..8177a08504b0b --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs new file mode 100644 index 0000000000000..031d70fdc8897 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs @@ -0,0 +1,29 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const _X: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 2); + //~^ error: evaluation of constant value failed +}; +const _Y: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 2, 4); + //~^ error: evaluation of constant value failed +}; + +const _Z: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 3, 4); + //~^ error: evaluation of constant value failed +}; + +const _W: () = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + intrinsics::const_deallocate(ptr, 4, 3); + //~^ error: evaluation of constant value failed +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr new file mode 100644 index 0000000000000..650b409b1908a --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 + | +LL | intrinsics::const_deallocate(ptr, 2, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 + | +LL | intrinsics::const_deallocate(ptr, 3, 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4 + +error[E0080]: evaluation of constant value failed + --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 + | +LL | intrinsics::const_deallocate(ptr, 4, 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. From 5e97fc9aa265cb523a16cbe035c638eb35257cf5 Mon Sep 17 00:00:00 2001 From: woppopo Date: Sun, 23 Jan 2022 23:04:39 +0900 Subject: [PATCH 02/14] Make `NonNull::new` `const` --- library/core/src/ptr/non_null.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3a7e99faccf23..3f5d3f62c9604 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -211,8 +211,9 @@ impl NonNull { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] + #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")] #[inline] - pub fn new(ptr: *mut T) -> Option { + pub const fn new(ptr: *mut T) -> Option { if !ptr.is_null() { // SAFETY: The pointer is already checked and is not null Some(unsafe { Self::new_unchecked(ptr) }) From d442a372621f70bd63f42917becf184387cfe3d4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Jan 2022 17:09:18 +0100 Subject: [PATCH 03/14] Fix invalid extra dot after version if no source --- src/librustdoc/html/render/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 32e4a82918421..0b6faa4b13ed2 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1676,11 +1676,12 @@ fn render_rightside( containing_item.stable_since(tcx), const_stable_since, ); - if has_stability { + let mut tmp_buf = Buffer::empty_from(w); + write_srclink(cx, item, &mut tmp_buf); + if has_stability && !tmp_buf.is_empty() { w.write_str(" · "); } - - write_srclink(cx, item, w); + w.push_buffer(tmp_buf); w.write_str(""); } From 066fcb6fd55010b01d9b63b74336e5e38fc6940f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Jan 2022 17:20:59 +0100 Subject: [PATCH 04/14] Add test when there is no source code link after version --- .../version-separator-without-source.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/rustdoc/version-separator-without-source.rs diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs new file mode 100644 index 0000000000000..bffe5030a84fd --- /dev/null +++ b/src/test/rustdoc/version-separator-without-source.rs @@ -0,0 +1,23 @@ +#![doc(html_no_source)] +#![feature(staged_api)] +#![stable(feature = "bar", since = "1.0")] +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub fn foo() {} + +// @has foo/struct.Bar.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub struct Bar; + +impl Bar { + // @has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0' + // @!has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0 ·' + #[stable(feature = "foobar", since = "2.0")] + pub fn bar() {} +} From 29932db09bb985072dc68d9d4e4acab09e69562a Mon Sep 17 00:00:00 2001 From: woppopo Date: Wed, 26 Jan 2022 13:06:09 +0900 Subject: [PATCH 05/14] `const_deallocate`: Don't deallocate memory allocated in an another const. Does nothing at runtime. `const_allocate`: Returns a null pointer at runtime. --- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 10 +++++++ .../src/const_eval/machine.rs | 20 ++++++++++---- library/core/src/intrinsics.rs | 5 ++-- library/core/tests/intrinsics.rs | 13 ++++++++++ library/core/tests/lib.rs | 1 + .../const-eval/heap/alloc_intrinsic_errors.rs | 3 +-- .../heap/alloc_intrinsic_errors.stderr | 2 +- .../const-eval/heap/dealloc_intrinsic.rs | 26 ++++++++++++++++++- 8 files changed, 69 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3657f80c2de80..c654232c10a57 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + sym::const_allocate => { + // returns a null pointer at runtime. + bx.const_null(bx.type_i8p()) + } + + sym::const_deallocate => { + // nop at runtime. + return; + } + // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst name if name_str.starts_with("atomic_") => { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 62eaf3333404e..89717b75f1281 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -358,11 +358,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), }; - ecx.memory.deallocate( - ptr, - Some((size, align)), - interpret::MemoryKind::Machine(MemoryKind::Heap), - )?; + // If an allocation is created in an another const, + // we don't deallocate it. + let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?; + let is_allocated_in_another_const = matches!( + ecx.tcx.get_global_alloc(alloc_id), + Some(interpret::GlobalAlloc::Memory(_)) + ); + + if !is_allocated_in_another_const { + ecx.memory.deallocate( + ptr, + Some((size, align)), + interpret::MemoryKind::Machine(MemoryKind::Heap), + )?; + } } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 10b5e06fc505c..b03f1268e363d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1914,12 +1914,13 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; - /// Allocate at compile time. Should not be called at runtime. + /// Allocate at compile time. + /// Returns a null pointer at runtime. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; /// Deallocate a memory which allocated by `intrinsics::const_allocate` at compile time. - /// Should not be called at runtime. + /// Does nothing at runtime. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[cfg(not(bootstrap))] pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index 7a2e4e2906557..e5b6fa7f73258 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -80,3 +80,16 @@ fn test_hints_in_const_contexts() { assert!(42u32 == core::hint::black_box(42u32)); } } + +#[cfg(not(bootstrap))] +#[test] +fn test_const_dealocate_at_runtime() { + use core::intrinsics::const_deallocate; + const X: &u32 = &42u32; + let x = &0u32; + unsafe { + const_deallocate(X as *const _ as *mut u8, 4, 4); // nop + const_deallocate(x as *const _ as *mut u8, 4, 4); // nop + const_deallocate(core::ptr::null_mut(), 1, 1); // nop + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 841c114063dc1..1d49d7e47cb69 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,6 +13,7 @@ #![feature(const_bool_to_option)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_assume_init_read)] diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs index 1a1d9a6d540d8..ac9e8b64b4897 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -6,11 +6,10 @@ use std::intrinsics; const FOO: i32 = foo(); const fn foo() -> i32 { unsafe { - let _ = intrinsics::const_allocate(4, 3) as * mut i32; + let _ = intrinsics::const_allocate(4, 3) as *mut i32; //~^ error: evaluation of constant value failed } 1 - } fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr index 74fb65ca1a658..2628a78455c76 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed LL | const FOO: i32 = foo(); | ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18 ... -LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32; +LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | align has to be a power of 2, `3` is not a power of 2 diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs index b7c2b75264429..aac90cd54cc41 100644 --- a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -1,6 +1,7 @@ // run-pass #![feature(core_intrinsics)] #![feature(const_heap)] +#![feature(const_mut_refs)] use std::intrinsics; @@ -9,4 +10,27 @@ const _X: () = unsafe { intrinsics::const_deallocate(ptr, 4, 4); }; -fn main() {} +const Y: &u32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4) as *mut u32; + *ptr = 42; + &*ptr +}; + +const Z: &u32 = &42; + +const _Z: () = unsafe { + let ptr1 = Y as *const _ as *mut u8; + intrinsics::const_deallocate(ptr1, 4, 4); // nop + intrinsics::const_deallocate(ptr1, 2, 4); // nop + intrinsics::const_deallocate(ptr1, 4, 2); // nop + + let ptr2 = Z as *const _ as *mut u8; + intrinsics::const_deallocate(ptr2, 4, 4); // nop + intrinsics::const_deallocate(ptr2, 2, 4); // nop + intrinsics::const_deallocate(ptr2, 4, 2); // nop +}; + +fn main() { + assert_eq!(*Y, 42); + assert_eq!(*Z, 42); +} From da0d506ace5dc5ec36cd1eafa37a0657fa61442e Mon Sep 17 00:00:00 2001 From: Tomoaki Kawada Date: Fri, 28 Jan 2022 14:53:54 +0900 Subject: [PATCH 06/14] kmc-solid: Implement `FileDesc::duplicate` --- library/std/src/sys/solid/abi/sockets.rs | 3 +++ library/std/src/sys/solid/net.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs index 7c21d0dd25e03..eb06a6dd927e6 100644 --- a/library/std/src/sys/solid/abi/sockets.rs +++ b/library/std/src/sys/solid/abi/sockets.rs @@ -175,6 +175,9 @@ extern "C" { #[link_name = "SOLID_NET_Close"] pub fn close(s: c_int) -> c_int; + #[link_name = "SOLID_NET_Dup"] + pub fn dup(s: c_int) -> c_int; + #[link_name = "SOLID_NET_GetPeerName"] pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index 63ba6341c796c..c91ecce4d728b 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -107,7 +107,7 @@ impl FileDesc { } fn duplicate(&self) -> io::Result { - super::unsupported() + cvt(unsafe { netc::dup(self.fd) }).map(Self::new) } } From 7a7144f4136897605842886b1ca51515e75d654e Mon Sep 17 00:00:00 2001 From: woppopo Date: Fri, 28 Jan 2022 17:27:33 +0900 Subject: [PATCH 07/14] test_const_allocate_at_runtime --- library/core/tests/intrinsics.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index e5b6fa7f73258..df940de479532 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -83,7 +83,16 @@ fn test_hints_in_const_contexts() { #[cfg(not(bootstrap))] #[test] -fn test_const_dealocate_at_runtime() { +fn test_const_allocate_at_runtime() { + use core::intrinsics::const_allocate; + unsafe { + assert!(const_allocate(4, 4).is_null()); + } +} + +#[cfg(not(bootstrap))] +#[test] +fn test_const_deallocate_at_runtime() { use core::intrinsics::const_deallocate; const X: &u32 = &42u32; let x = &0u32; From cdd0873db690cbcea1e5a011bbfc7fc94c5d5a6e Mon Sep 17 00:00:00 2001 From: woppopo Date: Fri, 28 Jan 2022 18:41:35 +0900 Subject: [PATCH 08/14] Add a test case for using NonNull::new in const context --- library/core/tests/lib.rs | 2 ++ library/core/tests/ptr.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 841c114063dc1..e5ae65f1ab5e0 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,7 +16,9 @@ #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_assume_init_read)] +#![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index b9c0d75b702e5..bbfd2d64dda40 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -274,6 +274,21 @@ fn test_unsized_nonnull() { assert!(ys == zs); } +#[test] +fn test_const_nonnull_new() { + const { + assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none()); + + let value = &mut 0u32; + let mut ptr = NonNull::new(value).unwrap(); + unsafe { *ptr.as_mut() = 42 }; + + let reference = unsafe { &*ptr.as_ref() }; + assert!(*reference == *value); + assert!(*reference == 42); + }; +} + #[test] #[allow(warnings)] // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the From 9d65342591d344c5358ee1aa2dd22c72748549f9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 28 Jan 2022 15:02:47 +0100 Subject: [PATCH 09/14] fix nit --- compiler/rustc_middle/src/ty/sty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 20db25f7899dd..f70fde2a040a1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1810,7 +1810,7 @@ impl<'tcx> TyS<'tcx> { pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { Array(ty, _) | Slice(ty) => ty, - Str => tcx.mk_mach_uint(ty::UintTy::U8), + Str => tcx.types.u8, _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), } } From f9e0eb3b94776a80de110b1820d15270fadec633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 28 Jan 2022 16:56:05 +0100 Subject: [PATCH 10/14] remove unused `jemallocator` crate --- Cargo.lock | 11 ----------- compiler/rustc/Cargo.toml | 6 +----- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 738f33d3fa219..b70e82f36568f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3319,7 +3319,6 @@ dependencies = [ "rustc_codegen_ssa", "rustc_driver", "tikv-jemalloc-sys", - "tikv-jemallocator", ] [[package]] @@ -5164,16 +5163,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tikv-jemallocator" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c14a5a604eb8715bc5785018a37d00739b180bcf609916ddf4393d33d49ccdf" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - [[package]] name = "time" version = "0.1.43" diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 277cf0f51d378..696c003a587ac 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -15,11 +15,7 @@ version = '0.4.0' optional = true features = ['unprefixed_malloc_on_supported_platforms'] -[dependencies.tikv-jemallocator] -version = '0.4.0' -optional = true - [features] -jemalloc = ['tikv-jemalloc-sys', 'tikv-jemallocator'] +jemalloc = ['tikv-jemalloc-sys'] llvm = ['rustc_driver/llvm'] max_level_info = ['rustc_driver/max_level_info'] From 4f8b9a41263ebd8469c626d36bf10034ad99ea8c Mon Sep 17 00:00:00 2001 From: Daniel Conley Date: Fri, 28 Jan 2022 11:00:56 -0500 Subject: [PATCH 11/14] Add Explanation For Error E0772 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0772.md | 89 +++++++++++++++++++ ...atic-bound-needing-more-suggestions.stderr | 3 +- ...yn-trait-with-implicit-static-bound.stderr | 3 +- 4 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0772.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 724e3f7fed399..5dafbb26b83c7 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -471,6 +471,7 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0772: include_str!("./error_codes/E0772.md"), E0773: include_str!("./error_codes/E0773.md"), E0774: include_str!("./error_codes/E0774.md"), E0775: include_str!("./error_codes/E0775.md"), @@ -641,5 +642,4 @@ E0785: include_str!("./error_codes/E0785.md"), // E0723, unstable feature in `const` context E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md new file mode 100644 index 0000000000000..262e52351ef01 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0772.md @@ -0,0 +1,89 @@ +A trait object has some specific lifetime `'1`, but it was used in a way that +requires it to have a `'static` lifetime. + +Example of erroneous code: + +```compile_fail,E0772 +trait BooleanLike {} +trait Person {} + +impl BooleanLike for bool {} + +impl dyn Person { + fn is_cool(&self) -> bool { + // hey you, you're pretty cool + true + } +} + +fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike { + // error: `person` has an anonymous lifetime `'p` but calling + // `print_cool_fn` introduces an implicit `'static` lifetime + // requirement + person.is_cool() +} +``` + +The trait object `person` in the function `get_is_cool`, while already being +behind a reference with lifetime `'p`, also has it's own implicit lifetime, +`'2`. + +Lifetime `'2` represents the data the trait object might hold inside, for +example: + +``` +trait MyTrait {} + +struct MyStruct<'a>(&'a i32); + +impl<'a> MyTrait for MyStruct<'a> {} +``` + +With this scenario, if a trait object of `dyn MyTrait + '2` was made from +`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the +trait object's internal data to be accessed safely from any trait methods. This +rule also goes for any lifetime any struct made into a trait object may have. + +In the implementation for `dyn Person`, the `'2` lifetime representing the +internal data was ommitted, meaning that the compiler inferred the lifetime +`'static`. As a result, the implementation's `is_cool` is inferred by the +compiler to look like this: + +``` +# trait Person {} +# +# impl dyn Person { +fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()} +# } +``` + +While the `get_is_cool` function is inferred to look like this: + +``` +# trait Person {} +# trait BooleanLike {} +# +fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R { + unimplemented!() +} +``` + +Which brings us to the core of the problem; the assignment of type +`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible. + +Fixing it is as simple as being generic over lifetime `'2`, as to prevent the +compiler from inferring it as `'static`: + +``` +# trait Person {} +# +impl<'d> dyn Person + 'd {/* ... */} + +// This works too, and is more elegant: +//impl dyn Person + '_ {/* ... */} +``` + +See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for +more information on trait object lifetimes. + +[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 2961d8d7eacc9..bd2e57517d786 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -38,4 +38,5 @@ LL | impl MyTrait for Box + '_> { error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0515`. +Some errors have detailed explanations: E0515, E0772. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 6d9f0811b2735..ea482ced98d62 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -131,4 +131,5 @@ LL | impl MyTrait for Box { error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0759`. +Some errors have detailed explanations: E0759, E0772. +For more information about an error, try `rustc --explain E0759`. From fa11fb4c5afc10b3dfe4129ca0f882b80131b49a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 29 Jan 2022 10:44:18 +0100 Subject: [PATCH 12/14] Update browser-ui-test version to 0.5.8 --- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index d4701a25614cd..c547e12f5b6ce 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.5.3 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ From aee9ebae968f971e08a1300460e36c161b56787a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 29 Jan 2022 10:44:27 +0100 Subject: [PATCH 13/14] Extend theme change GUI test --- src/test/rustdoc-gui/theme-change.goml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml index 60d089ffa3758..73edee64e4372 100644 --- a/src/test/rustdoc-gui/theme-change.goml +++ b/src/test/rustdoc-gui/theme-change.goml @@ -9,3 +9,19 @@ click: "#theme-choices > button:last-child" wait-for: 500 // should be the light theme so let's check the color assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) + +goto: file://|DOC_PATH|/settings.html +click: "#theme-light" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } + +click: "#theme-dark" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +click: "#theme-ayu" +wait-for: 500 +assert-css: ("body", { "background-color": "rgb(15, 20, 25)" }) +assert-local-storage: { "rustdoc-theme": "ayu" } From 9728cc4e26c936e17a107ceeccf029bde4e7e1f0 Mon Sep 17 00:00:00 2001 From: woppopo Date: Sat, 29 Jan 2022 19:13:23 +0900 Subject: [PATCH 14/14] Document about some behaviors of `const_(de)allocate` and add some tests. --- library/core/src/intrinsics.rs | 22 +++++++++++++++---- .../heap/alloc_intrinsic_zero_sized.rs | 16 ++++++++++++++ .../heap/dealloc_intrinsic_zero_sized.rs | 17 ++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs create mode 100644 src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b03f1268e363d..b5228397f0a99 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1914,13 +1914,27 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; - /// Allocate at compile time. - /// Returns a null pointer at runtime. + /// Allocates a block of memory at compile time. + /// At runtime, just returns a null pointer. + /// + /// # Safety + /// + /// - The `align` argument must be a power of two. + /// - At compile time, a compile error occurs if this constraint is violated. + /// - At runtime, it is not checked. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; - /// Deallocate a memory which allocated by `intrinsics::const_allocate` at compile time. - /// Does nothing at runtime. + /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time. + /// At runtime, does nothing. + /// + /// # Safety + /// + /// - The `align` argument must be a power of two. + /// - At compile time, a compile error occurs if this constraint is violated. + /// - At runtime, it is not checked. + /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it. + /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[cfg(not(bootstrap))] pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize); diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs new file mode 100644 index 0000000000000..407e69d41a0fa --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs @@ -0,0 +1,16 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +struct ZST; + +fn main() { + const { + unsafe { + let _ = intrinsics::const_allocate(0, 0) as *mut ZST; + } + } +} diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs new file mode 100644 index 0000000000000..84fb4d2ea870f --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(inline_const)] + +use std::intrinsics; + +fn main() { + const { + unsafe { + let ptr1 = intrinsics::const_allocate(0, 0); + let ptr2 = intrinsics::const_allocate(0, 0); + intrinsics::const_deallocate(ptr1, 0, 0); + intrinsics::const_deallocate(ptr2, 0, 0); + } + } +}