From 5f443df4044532d95c23aa8d97f2748ca287378f Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Sat, 2 Nov 2024 11:39:29 -0600 Subject: [PATCH 01/10] Add #[rustc_as_ptr] attribute --- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ compiler/rustc_passes/src/check_attr.rs | 3 +++ compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0069b07ad62..95cb7f4fff5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -875,6 +875,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items, "lang items are subject to change", ), + rustc_attr!( + rustc_as_ptr, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, + "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations." + ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0a2926c0404..8d70c9db12c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_std_internal_symbol(attr, span, target) } [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_as_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 890c4fdafef..dde6b83c151 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1652,6 +1652,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, + rustc_as_ptr, rustc_attrs, rustc_autodiff, rustc_box, From 37c30aeb45d33b14dadb6c06c3f71b8e047bd2fe Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:27:09 -0700 Subject: [PATCH 02/10] Check for #[rustc_as_ptr] attribute instead of searching for function names Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_lint/src/dangling.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index a34c3e26778..09fe709e845 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -133,10 +133,11 @@ impl DanglingPointerSearcher<'_, '_> { fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind - && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr) + && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr) && is_temporary_rvalue(receiver) && let ty = cx.typeck_results().expr_ty(receiver) - && is_interesting(cx.tcx, ty) + && owns_allocation(cx.tcx, ty) { // FIXME: use `emit_node_lint` when `#[primary_span]` is added. cx.tcx.emit_node_span_lint( @@ -201,14 +202,14 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { // Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, // or any of the above in arbitrary many nested Box'es. -fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { +fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { if ty.is_array() { true } else if let Some(inner) = ty.boxed_ty() { inner.is_slice() || inner.is_str() || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) - || is_interesting(tcx, inner) + || owns_allocation(tcx, inner) } else if let Some(def) = ty.ty_adt_def() { for lang_item in [LangItem::String, LangItem::MaybeUninit] { if tcx.is_lang_item(def.did(), lang_item) { From fdef65bf6e36fcecd3df71d3a630c306f7acc784 Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:05:56 -0700 Subject: [PATCH 03/10] Tag relevant functions with #[rustc_as_ptr] attribute --- library/alloc/src/boxed.rs | 2 ++ library/alloc/src/vec/mod.rs | 2 ++ library/core/src/cell.rs | 4 ++++ library/core/src/ffi/c_str.rs | 1 + library/core/src/mem/maybe_uninit.rs | 2 ++ library/core/src/slice/mod.rs | 2 ++ library/core/src/str/mod.rs | 2 ++ 7 files changed, 15 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e4956c7c53c..425d5f2ecfb 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1499,6 +1499,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1547,6 +1548,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 07a1bd49321..990b7e8f761 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1662,6 +1662,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1724,6 +1725,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7e6c042274d..b3aaba034fe 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -587,6 +587,7 @@ impl Cell { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1149,6 +1150,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() @@ -2157,6 +2159,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of @@ -2303,6 +2306,7 @@ impl SyncUnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 93dd351b029..f882b240e79 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -501,6 +501,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4252ef0103..5accbc3621d 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -529,6 +529,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -570,6 +571,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 27e51afa800..5ab05a9f641 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -735,6 +735,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -766,6 +767,7 @@ impl [T] { #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_allow_const_fn_unstable(const_mut_refs)] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9ef99e9dae8..fd80b33101f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -371,6 +371,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -388,6 +389,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut u8 { From 8ec94d30e514a794154ad467dd5275a78811efcc Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:30:25 -0700 Subject: [PATCH 04/10] Update dangling pointer tests --- compiler/rustc_lint/src/dangling.rs | 7 +-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cell.rs | 1 + .../types.rs | 7 ++- .../types.stderr | 54 +++++++++++++------ 5 files changed, 50 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 09fe709e845..21966758b10 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -211,13 +211,14 @@ fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) || owns_allocation(tcx, inner) } else if let Some(def) = ty.ty_adt_def() { - for lang_item in [LangItem::String, LangItem::MaybeUninit] { + for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] { if tcx.is_lang_item(def.did(), lang_item) { return true; } } - tcx.get_diagnostic_name(def.did()) - .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell)) + tcx.get_diagnostic_name(def.did()).is_some_and(|name| { + matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::sync_unsafe_cell) + }) } else { false } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dde6b83c151..786be851c5d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1930,6 +1930,7 @@ symbols! { surface_async_drop_in_place, sym, sync, + sync_unsafe_cell, synthetic, t32, target, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b3aaba034fe..e595ea56392 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2273,6 +2273,7 @@ impl, U> DispatchFromDyn> for UnsafeCell /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] +#[rustc_diagnostic_item = "sync_unsafe_cell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell { value: UnsafeCell, diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs index 2b515d3e6d5..17c3eca89e2 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -1,6 +1,7 @@ #![deny(dangling_pointers_from_temporaries)] +#![feature(sync_unsafe_cell)] -use std::cell::Cell; +use std::cell::{Cell, SyncUnsafeCell, UnsafeCell}; use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; @@ -47,6 +48,10 @@ fn main() { //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped declval::>().as_ptr(); //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + declval::>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped + declval::>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped declval::>().as_ptr(); declval::().as_ptr(); } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index c582a4c6540..250ed6dc9e3 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -1,5 +1,5 @@ error: a dangling pointer will be produced because the temporary `CString` will be dropped - --> $DIR/types.rs:20:26 + --> $DIR/types.rs:21:26 | LL | declval::().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -15,7 +15,7 @@ LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a dangling pointer will be produced because the temporary `String` will be dropped - --> $DIR/types.rs:22:25 + --> $DIR/types.rs:23:25 | LL | declval::().as_ptr(); | ------------------- ^^^^^^ this pointer will immediately be invalid @@ -26,7 +26,7 @@ LL | declval::().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped - --> $DIR/types.rs:24:26 + --> $DIR/types.rs:25:26 | LL | declval::>().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -37,7 +37,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:26:31 + --> $DIR/types.rs:27:31 | LL | declval::>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -48,7 +48,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped - --> $DIR/types.rs:28:28 + --> $DIR/types.rs:29:28 | LL | declval::>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -59,7 +59,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:30:27 + --> $DIR/types.rs:31:27 | LL | declval::>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -70,7 +70,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:32:28 + --> $DIR/types.rs:33:28 | LL | declval::>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -81,7 +81,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped - --> $DIR/types.rs:34:27 + --> $DIR/types.rs:35:27 | LL | declval::<[u8; 10]>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -92,7 +92,7 @@ LL | declval::<[u8; 10]>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped - --> $DIR/types.rs:36:32 + --> $DIR/types.rs:37:32 | LL | declval::>().as_ptr(); | -------------------------- ^^^^^^ this pointer will immediately be invalid @@ -103,7 +103,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>` will be dropped - --> $DIR/types.rs:38:31 + --> $DIR/types.rs:39:31 | LL | declval::>>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -114,7 +114,7 @@ LL | declval::>>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:40:30 + --> $DIR/types.rs:41:30 | LL | declval::>().as_ptr(); | ------------------------ ^^^^^^ this pointer will immediately be invalid @@ -125,7 +125,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>>>` will be dropped - --> $DIR/types.rs:42:43 + --> $DIR/types.rs:43:43 | LL | declval::>>>>().as_ptr(); | ------------------------------------- ^^^^^^ this pointer will immediately be invalid @@ -136,7 +136,7 @@ LL | declval::>>>>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Cell` will be dropped - --> $DIR/types.rs:44:27 + --> $DIR/types.rs:45:27 | LL | declval::>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -147,7 +147,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped - --> $DIR/types.rs:46:34 + --> $DIR/types.rs:47:34 | LL | declval::>().as_ptr(); | ---------------------------- ^^^^^^ this pointer will immediately be invalid @@ -158,7 +158,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped - --> $DIR/types.rs:48:33 + --> $DIR/types.rs:49:33 | LL | declval::>().as_ptr(); | --------------------------- ^^^^^^ this pointer will immediately be invalid @@ -168,5 +168,27 @@ LL | declval::>().as_ptr(); = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned = help: for more information, see -error: aborting due to 15 previous errors +error: a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped + --> $DIR/types.rs:51:33 + | +LL | declval::>().get(); + | --------------------------- ^^^ this pointer will immediately be invalid + | | + | this `UnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see + +error: a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped + --> $DIR/types.rs:53:37 + | +LL | declval::>().get(); + | ------------------------------- ^^^ this pointer will immediately be invalid + | | + | this `SyncUnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see + +error: aborting due to 17 previous errors From 24cc924af35945af57462ebeeba238ebcdf5e1ba Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:52:07 -0700 Subject: [PATCH 05/10] Remove as_mut_ptr symbol --- compiler/rustc_span/src/symbol.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 786be851c5d..dd969831253 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -410,7 +410,6 @@ symbols! { arm, arm_target_feature, array, - as_mut_ptr, as_ptr, as_ref, as_str, From 6f8fe7929aa3c7131180442dc7d90ea1be831204 Mon Sep 17 00:00:00 2001 From: omni Date: Mon, 18 Nov 2024 20:35:38 +0000 Subject: [PATCH 06/10] Make rustc --explain busybox less compatible busybox less does not support the -r flag and less(1) says: USE OF THE -r OPTION IS NOT RECOMMENDED. --- compiler/rustc_driver_impl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b6f7abed6f3..8dd043be6ad 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -577,7 +577,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { let mut cmd = Command::new(&pager_name); // FIXME: find if other pagers accept color options let mut print_formatted = if pager_name == "less" { - cmd.arg("-r"); + cmd.arg("-R"); true } else { ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name) From 0270580bc5d0c507b61bdf5cacce67b78fde207a Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:09:13 +0100 Subject: [PATCH 07/10] CI: use free runner in dist-aarch64-msvc --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 340dfd67b7d..eea97e98cc2 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -477,7 +477,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c + <<: *job-windows - image: dist-i686-mingw env: From 01fd384d5800deb1e96b0d8921e82317e9fcdb8b Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:32:13 -0700 Subject: [PATCH 08/10] Correct comments concerning updated dangling pointer lint --- compiler/rustc_lint/src/dangling.rs | 13 +++++-------- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/cell.rs | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 21966758b10..e3e51ba263d 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -43,13 +43,10 @@ declare_lint! { } /// FIXME: false negatives (i.e. the lint is not emitted when it should be) -/// 1. Method calls that are not checked for: -/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`] -/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`] -/// 2. Ways to get a temporary that are not recognized: +/// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` /// - `owning_temporary[index]` -/// 3. No checks for ref-to-ptr conversions: +/// 2. No checks for ref-to-ptr conversions: /// - `&raw [mut] temporary` /// - `&temporary as *(const|mut) _` /// - `ptr::from_ref(&temporary)` and friends @@ -200,8 +197,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { } } -// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, -// or any of the above in arbitrary many nested Box'es. +// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, UnsafeCell, +// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es. fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { if ty.is_array() { true @@ -217,7 +214,7 @@ fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { } } tcx.get_diagnostic_name(def.did()).is_some_and(|name| { - matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::sync_unsafe_cell) + matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell) }) } else { false diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dd969831253..a7c43a20840 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -316,6 +316,7 @@ symbols! { SubdiagMessage, Subdiagnostic, Sync, + SyncUnsafeCell, T, Target, ToOwned, @@ -1929,7 +1930,6 @@ symbols! { surface_async_drop_in_place, sym, sync, - sync_unsafe_cell, synthetic, t32, target, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e595ea56392..20904c9bc76 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2273,7 +2273,7 @@ impl, U> DispatchFromDyn> for UnsafeCell /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] -#[rustc_diagnostic_item = "sync_unsafe_cell"] +#[rustc_diagnostic_item = "SyncUnsafeCell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell { value: UnsafeCell, From df94818366648595e9cf6fa4fa7d061a5adfd780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2024 15:32:11 +0100 Subject: [PATCH 09/10] lints_that_dont_need_to_run: never skip future-compat-reported lints --- compiler/rustc_lint/src/levels.rs | 22 ++++++++++++---------- compiler/rustc_lint_defs/src/lib.rs | 14 ++++++++++++++ compiler/rustc_middle/src/lint.rs | 7 +------ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 97a95787422..4b1dafbdbee 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -123,17 +123,19 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { let dont_need_to_run: FxIndexSet = store .get_lints() .into_iter() + .filter(|lint| { + // Lints that show up in future-compat reports must always be run. + let has_future_breakage = + lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage()); + !has_future_breakage && !lint.eval_always + }) .filter_map(|lint| { - if !lint.eval_always { - let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); - if matches!(lint_level, (Level::Allow, ..)) - || (matches!(lint_level, (.., LintLevelSource::Default))) - && lint.default_level(tcx.sess.edition()) == Level::Allow - { - Some(LintId::of(lint)) - } else { - None - } + let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); + if matches!(lint_level, (Level::Allow, ..)) + || (matches!(lint_level, (.., LintLevelSource::Default))) + && lint.default_level(tcx.sess.edition()) == Level::Allow + { + Some(LintId::of(lint)) } else { None } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index eac4afee050..c74fceeedba 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -466,6 +466,20 @@ impl FutureIncompatibilityReason { | FutureIncompatibilityReason::Custom(_) => None, } } + + pub fn has_future_breakage(self) -> bool { + match self { + FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true, + + FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + | FutureIncompatibilityReason::FutureReleaseSemanticsChange + | FutureIncompatibilityReason::EditionError(_) + | FutureIncompatibilityReason::EditionSemanticsChange(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseError(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_) + | FutureIncompatibilityReason::Custom(_) => false, + } + } } impl FutureIncompatibleInfo { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 92ba6ceee93..971d036fa69 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -290,12 +290,7 @@ pub fn lint_level( let has_future_breakage = future_incompatible.map_or( // Default allow lints trigger too often for testing. sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, - |incompat| { - matches!( - incompat.reason, - FutureIncompatibilityReason::FutureReleaseErrorReportInDeps - ) - }, + |incompat| incompat.reason.has_future_breakage(), ); // Convert lint level to error level. From def7ed08e7b27288bc861384ec166ebc5a419abc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 29 Oct 2024 17:51:38 +0000 Subject: [PATCH 10/10] Implement ~const Fn trait goals in the new solver --- compiler/rustc_middle/src/ty/context.rs | 6 +- .../src/solve/assembly/structural_traits.rs | 70 +++++++++++++++ .../src/solve/effect_goals.rs | 55 ++++++++++-- .../src/solve/normalizes_to/mod.rs | 10 ++- .../src/solve/trait_goals.rs | 10 ++- compiler/rustc_type_ir/src/interner.rs | 3 +- .../const-traits/const-fns-are-early-bound.rs | 90 ------------------- .../effects/minicore-const-fn-early-bound.rs | 22 +++++ .../const-traits/effects/minicore-fn-fail.rs | 21 +++++ .../effects/minicore-fn-fail.stderr | 9 ++ .../const-traits/effects/minicore-works.rs | 6 ++ 11 files changed, 193 insertions(+), 109 deletions(-) delete mode 100644 tests/ui/traits/const-traits/const-fns-are-early-bound.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-fn-fail.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ba1bf2822f..77a40762903 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -374,7 +374,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } - fn is_const_impl(self, def_id: DefId) -> bool { + fn impl_is_const(self, def_id: DefId) -> bool { + self.is_conditionally_const(def_id) + } + + fn fn_is_const(self, def_id: DefId) -> bool { self.is_conditionally_const(def_id) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 5c1a7852dc0..a56febec48c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -633,6 +633,76 @@ fn coroutine_closure_to_ambiguous_coroutine( ) } +/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs +/// to return different information (namely, the def id and args) so that we can +/// create const conditions. +/// +/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable` +/// would be wasteful. +pub(in crate::solve) fn extract_fn_def_from_const_callable( + cx: I, + self_ty: I::Ty, +) -> Result<(ty::Binder, I::DefId, I::GenericArgs), NoSolution> { + match self_ty.kind() { + ty::FnDef(def_id, args) => { + let sig = cx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() + && !cx.has_target_features(def_id) + && cx.fn_is_const(def_id) + { + Ok(( + sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())), + def_id, + args, + )) + } else { + return Err(NoSolution); + } + } + // `FnPtr`s are not const for now. + ty::FnPtr(..) => { + return Err(NoSolution); + } + // `Closure`s are not const for now. + ty::Closure(..) => { + return Err(NoSolution); + } + // `CoroutineClosure`s are not const for now. + ty::CoroutineClosure(..) => { + return Err(NoSolution); + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Pat(_, _) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => return Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0912e5effa6..282ca2fedbc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -3,15 +3,15 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; -use super::assembly::Candidate; +use super::assembly::{Candidate, structural_traits}; use crate::delegate::SolverDelegate; -use crate::solve::assembly::{self}; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, - QueryResult, + QueryResult, assembly, }; impl assembly::GoalKind for ty::HostEffectPredicate @@ -142,7 +142,7 @@ where ty::ImplPolarity::Positive => {} }; - if !cx.is_const_impl(impl_def_id) { + if !cx.impl_is_const(impl_def_id) { return Err(NoSolution); } @@ -207,7 +207,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - todo!("Copy/Clone is not yet const") + Err(NoSolution) } fn consider_builtin_pointer_like_candidate( @@ -225,11 +225,48 @@ where } fn consider_builtin_fn_trait_candidates( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, _kind: rustc_type_ir::ClosureKind, ) -> Result, NoSolution> { - todo!("Fn* are not yet const") + let cx = ecx.cx(); + + let self_ty = goal.predicate.self_ty(); + let (inputs_and_output, def_id, args) = + structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| { + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) + }); + let requirements = cx + .const_conditions(def_id) + .iter_instantiated(cx, args) + .map(|trait_ref| { + ( + GoalSource::ImplWhereBound, + goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), + ) + }) + .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]); + + let pred = inputs_and_output + .map_bound(|(inputs, _)| { + ty::TraitRef::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + Ty::new_tup(cx, inputs.as_slice()), + ]) + }) + .to_host_effect_clause(cx, goal.predicate.constness); + + Self::probe_and_consider_implied_clause( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + pred, + requirements, + ) } fn consider_builtin_async_fn_trait_candidates( @@ -314,7 +351,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - unreachable!("Destruct is not const") + Err(NoSolution) } fn consider_builtin_transmute_candidate( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 129744b4db7..8a01659953d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -394,6 +394,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -408,8 +411,6 @@ where }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -438,6 +439,9 @@ where goal_kind, env_region, )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty]) @@ -494,8 +498,6 @@ where ) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5f740590712..e64d4eed9d8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -326,6 +326,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -335,8 +338,6 @@ where ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -364,6 +365,9 @@ where // This region doesn't matter because we're throwing away the coroutine type Region::new_static(cx), )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [ @@ -380,8 +384,6 @@ where ]) }) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f988f003c0f..6e6cf91d855 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -223,7 +223,8 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>; - fn is_const_impl(self, def_id: Self::DefId) -> bool; + fn impl_is_const(self, def_id: Self::DefId) -> bool; + fn fn_is_const(self, def_id: Self::DefId) -> bool; fn const_conditions( self, def_id: Self::DefId, diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs deleted file mode 100644 index c26eaf67454..00000000000 --- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs +++ /dev/null @@ -1,90 +0,0 @@ -//@ known-bug: #110395 -//@ failure-status: 101 -//@ dont-check-compiler-stderr -// FIXME(const_trait_impl) check-pass -//@ compile-flags: -Znext-solver - -#![crate_type = "lib"] -#![allow(internal_features, incomplete_features)] -#![no_std] -#![no_core] -#![feature( - auto_traits, - const_trait_impl, - effects, - lang_items, - no_core, - staged_api, - unboxed_closures, - rustc_attrs, - marker_trait_attr, -)] -#![stable(feature = "minicore", since = "1.0.0")] - -fn test() { - fn is_const_fn(_: F) - where - F: const FnOnce<()>, - { - } - - const fn foo() {} - - is_const_fn(foo); -} - -/// ---------------------------------------------------------------------- /// -/// Const fn trait definitions - -#[const_trait] -#[lang = "fn"] -#[rustc_paren_sugar] -trait Fn: ~const FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_mut"] -#[rustc_paren_sugar] -trait FnMut: ~const FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_once"] -#[rustc_paren_sugar] -trait FnOnce { - #[lang = "fn_once_output"] - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -/// ---------------------------------------------------------------------- /// -/// All this other stuff needed for core. Unrelated to test. - -#[lang = "destruct"] -#[const_trait] -trait Destruct {} - -#[lang = "freeze"] -unsafe auto trait Freeze {} - -#[lang = "drop"] -#[const_trait] -trait Drop { - fn drop(&mut self); -} - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} - -#[lang = "tuple_trait"] -trait Tuple {} - -#[lang = "legacy_receiver"] -trait LegacyReceiver {} - -impl LegacyReceiver for &T {} diff --git a/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs new file mode 100644 index 00000000000..ee47f92a0bc --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs @@ -0,0 +1,22 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort +//@ check-pass + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn is_const_fn(_: F) +where + F: const FnOnce(), +{ +} + +const fn foo() {} + +fn test() { + is_const_fn(foo); +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs new file mode 100644 index 00000000000..ae1cbc6ca58 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs @@ -0,0 +1,21 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +const fn call_indirect(t: &T) { t() } + +#[const_trait] +trait Foo {} +impl Foo for () {} +const fn foo() {} + +const fn test() { + call_indirect(&foo::<()>); + //~^ ERROR the trait bound `(): ~const Foo` is not satisfied +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr new file mode 100644 index 00000000000..cf158643b34 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): ~const Foo` is not satisfied + --> $DIR/minicore-fn-fail.rs:19:5 + | +LL | call_indirect(&foo::<()>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs index bfbfa8b2d05..c79b4fc07df 100644 --- a/tests/ui/traits/const-traits/effects/minicore-works.rs +++ b/tests/ui/traits/const-traits/effects/minicore-works.rs @@ -20,3 +20,9 @@ const fn test_op() { let _x = Add::add(1, 2); let _y = Custom + Custom; } + +const fn call_indirect(t: &T) { t() } + +const fn call() { + call_indirect(&call); +}