diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index d5d577d39d28b..9e29262042f21 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -42,6 +42,7 @@ mod format_foreign; mod global_allocator; mod iter; mod log_syntax; +mod offload; mod pattern_type; mod source_util; mod test; @@ -116,6 +117,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { eii_declaration: eii::eii_declaration, eii_shared_macro: eii::eii_shared_macro, global_allocator: global_allocator::expand, + offload_kernel: offload::expand_kernel, test: test::expand_test, test_case: test::expand_test_case, unsafe_eii: eii::unsafe_eii, diff --git a/compiler/rustc_builtin_macros/src/offload.rs b/compiler/rustc_builtin_macros/src/offload.rs new file mode 100644 index 0000000000000..9dbd2d45a93af --- /dev/null +++ b/compiler/rustc_builtin_macros/src/offload.rs @@ -0,0 +1,205 @@ +use rustc_ast::token::{Delimiter, Token, TokenKind}; +use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_ast::{AttrItem, ast}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_session::config::Offload; +use rustc_span::{Ident, Span, sym}; +use thin_vec::thin_vec; + +use crate::errors; + +fn compile_for_device(ecx: &mut ExtCtxt<'_>) -> bool { + ecx.sess.opts.unstable_opts.offload.contains(&Offload::Device) +} + +fn outer_normal_attr( + kind: &Box, + id: rustc_ast::AttrId, + span: Span, +) -> rustc_ast::Attribute { + let style = rustc_ast::AttrStyle::Outer; + let kind = rustc_ast::AttrKind::Normal(kind.clone()); + rustc_ast::Attribute { kind, id, style, span } +} + +fn extract_fn( + item: &Annotatable, +) -> Option<(ast::Visibility, ast::FnSig, Ident, ast::Generics, Option>)> { + match item { + Annotatable::Item(iitem) => match &iitem.kind { + ast::ItemKind::Fn(ast::Fn { sig, ident, generics, body, .. }) => { + Some((iitem.vis.clone(), sig.clone(), *ident, generics.clone(), body.clone())) + } + _ => None, + }, + _ => None, + } +} + +/// The `offload_kernel` macro expands the function into two separate definitions: +/// one on the host to handle the call, and one on the device for executing the kernel. +/// +/// ``` +/// #[offload_kernel] +/// fn foo(a: &[f32], b: &[f32], c: *mut f32) { +/// *c = a[0] + b[0]; +/// } +/// ``` +/// +/// This expands to the host-side function: +/// +/// ``` +/// #[unsafe(no_mangle)] +/// #[inline(never)] +/// fn foo(_: &[f32], _: &[f32], _: *mut f32) { +/// ::core::panicking::panic("not implemented") +/// } +/// ``` +/// +/// And the device-side kernel: +/// +/// ``` +/// #[rustc_offload_kernel] +/// #[unsafe(no_mangle)] +/// unsafe extern "gpu-kernel" fn foo(a: &[f32], b: &[f32], c: *mut f32) { +/// *c = a[0] + b[0]; +/// } +/// ``` +pub(crate) fn expand_kernel( + ecx: &mut ExtCtxt<'_>, + expand_span: Span, + _meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + let dcx = ecx.sess.dcx(); + + let Some((vis, sig, ident, generics, body)) = extract_fn(&item) else { + dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() }); + return vec![item]; + }; + + let span = ecx.with_def_site_ctxt(expand_span); + + // device function + let mut device_fn = Box::new(ast::Fn { + defaultness: ast::Defaultness::Implicit, + sig: sig.clone(), + ident, + generics: generics.clone(), + contract: None, + body, + define_opaque: None, + eii_impls: Default::default(), + }); + + let extern_gpu_kernel = ast::Extern::from_abi( + Some(ast::StrLit { + symbol: sym::gpu_kernel, + suffix: None, + symbol_unescaped: sym::gpu_kernel, + style: ast::StrStyle::Cooked, + span, + }), + span, + ); + device_fn.sig.header.ext = extern_gpu_kernel; + device_fn.sig.header.safety = ast::Safety::Unsafe(span); + + // rustc_offload_kernel attr + let rustc_offload_kernel_attr = + Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_offload_kernel))); + let rustc_offload_kernel = outer_normal_attr( + &rustc_offload_kernel_attr, + ecx.sess.psess.attr_id_generator.mk_attr_id(), + span, + ); + + // unsafe(no_mangle) attr + let unsafe_item = AttrItem { + unsafety: ast::Safety::Unsafe(span), + path: ast::Path::from_ident(Ident::new(sym::no_mangle, span)), + args: ast::AttrItemKind::Unparsed(ast::AttrArgs::Empty), + tokens: None, + }; + + let no_mangle_attr = Box::new(ast::NormalAttr { item: unsafe_item, tokens: None }); + let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); + let unsafe_no_mangle = outer_normal_attr(&no_mangle_attr, new_id, span); + + let device_item = { + let mut item = ecx.item( + span, + thin_vec![rustc_offload_kernel, unsafe_no_mangle], + ast::ItemKind::Fn(device_fn), + ); + item.vis = vis.clone(); + Annotatable::Item(item) + }; + + // unimplemented! body + let macro_expr = ecx.expr_macro_call( + span, + ecx.macro_call( + span, + ecx.path_global( + span, + [sym::std, sym::unimplemented].map(|s| Ident::new(s, span)).to_vec(), + ), + Delimiter::Parenthesis, + TokenStream::default(), + ), + ); + let stmt = ecx.stmt_expr(macro_expr); + let body = ecx.block(span, thin_vec![stmt]); + + // host function + let mut host_fn = Box::new(ast::Fn { + defaultness: ast::Defaultness::Implicit, + sig: sig.clone(), + ident, + generics: generics.clone(), + contract: None, + body: Some(body), + define_opaque: None, + eii_impls: Default::default(), + }); + + for param in host_fn.sig.decl.inputs.iter_mut() { + param.pat = Box::new(ecx.pat_wild(param.pat.span)); + } + + // inline(never) attr + let ts: Vec = vec![TokenTree::Token( + Token::new(TokenKind::Ident(sym::never, false.into()), span), + Spacing::Joint, + )]; + + let never_arg = ast::DelimArgs { + dspan: DelimSpan::from_single(span), + delim: Delimiter::Parenthesis, + tokens: TokenStream::from_iter(ts), + }; + + let inline_item = ast::AttrItem { + unsafety: ast::Safety::Default, + path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)), + args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)), + tokens: None, + }; + let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); + + let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); + let inline_never = outer_normal_attr(&inline_never_attr, new_id, span); + + let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); + let unsafe_no_mangle = outer_normal_attr(&no_mangle_attr, new_id, span); + + let host_item = { + let mut item = + ecx.item(span, thin_vec![unsafe_no_mangle, inline_never], ast::ItemKind::Fn(host_fn)); + item.vis = vis.clone(); + Annotatable::Item(item) + }; + + if compile_for_device(ecx) { vec![device_item] } else { vec![host_item] } +} diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c835ff7dbe070..0eb7db8dbed2d 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -842,9 +842,9 @@ where let mut values = Vec::with_capacity(adt.variants().len()); let mut normal_blocks = Vec::with_capacity(adt.variants().len()); let mut unwind_blocks = - if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants().len())) }; + Vec::with_capacity(if unwind.is_cleanup() { 0 } else { adt.variants().len() }); let mut dropline_blocks = - if dropline.is_none() { None } else { Some(Vec::with_capacity(adt.variants().len())) }; + Vec::with_capacity(if dropline.is_none() { 0 } else { adt.variants().len() }); let mut have_otherwise_with_drop_glue = false; let mut have_otherwise = false; @@ -880,7 +880,6 @@ where // I want to minimize the divergence between MSVC // and non-MSVC. - let unwind_blocks = unwind_blocks.as_mut().unwrap(); let unwind_ladder = vec![Unwind::InCleanup; fields.len() + 1]; let dropline_ladder: Vec> = vec![None; fields.len() + 1]; let halfladder = @@ -890,7 +889,7 @@ where let (normal, _, drop_bb) = self.drop_ladder(fields, succ, unwind, dropline); normal_blocks.push(normal); if dropline.is_some() { - dropline_blocks.as_mut().unwrap().push(drop_bb.unwrap()); + dropline_blocks.push(drop_bb.unwrap()); } } else { have_otherwise = true; @@ -911,28 +910,22 @@ where } else if !have_otherwise_with_drop_glue { normal_blocks.push(self.goto_block(succ, unwind)); if let Unwind::To(unwind) = unwind { - unwind_blocks.as_mut().unwrap().push(self.goto_block(unwind, Unwind::InCleanup)); + unwind_blocks.push(self.goto_block(unwind, Unwind::InCleanup)); } } else { normal_blocks.push(self.drop_block(succ, unwind)); if let Unwind::To(unwind) = unwind { - unwind_blocks.as_mut().unwrap().push(self.drop_block(unwind, Unwind::InCleanup)); + unwind_blocks.push(self.drop_block(unwind, Unwind::InCleanup)); } } ( self.adt_switch_block(adt, normal_blocks, &values, succ, unwind), unwind.map(|unwind| { - self.adt_switch_block( - adt, - unwind_blocks.unwrap(), - &values, - unwind, - Unwind::InCleanup, - ) + self.adt_switch_block(adt, unwind_blocks, &values, unwind, Unwind::InCleanup) }), dropline.map(|dropline| { - self.adt_switch_block(adt, dropline_blocks.unwrap(), &values, dropline, unwind) + self.adt_switch_block(adt, dropline_blocks, &values, dropline, unwind) }), ) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 68e29369e1f64..7263680c302f1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1040,6 +1040,7 @@ symbols! { global_asm, global_registration, globs, + gpu_kernel: "gpu-kernel", gpu_launch_sized_workgroup_mem, gt, guard, @@ -1424,6 +1425,7 @@ symbols! { of, off, offload, + offload_kernel, offset, offset_of, offset_of_enum, @@ -2163,6 +2165,7 @@ symbols! { underscore_imports, underscore_lifetimes, uniform_paths, + unimplemented, unit, universal_impl_trait, unix, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4d051a370c065..28b23bd37485a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -448,9 +448,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some((msg, span)) = type_def { err.span_label(span, msg); } - for note in notes { - // If it has a custom `#[rustc_on_unimplemented]` note, let's display it - err.note(note); + // `#[rustc_on_unimplemented]` notes for derivable traits (e.g. `Debug`'s + // "add `#[derive(Debug)]` to `X` or manually `impl Debug for X`") duplicate + // the `consider annotating X with #[derive(..)]` suggestion that + // `suggest_derive` emits below, so skip them when that suggestion will be + // shown. We keep the note otherwise (e.g. when a field isn't `Debug`, so + // the derive can't be suggested) to avoid leaving the diagnostic without + // actionable guidance. + let derive_suggestion_will_be_shown = main_trait_predicate + == leaf_trait_predicate + && self.can_suggest_derive(&obligation, leaf_trait_predicate); + if !derive_suggestion_will_be_shown { + for note in notes { + // If it has a custom `#[rustc_on_unimplemented]` note, let's display + // it. + err.note(note); + } } if let Some(s) = parent_label { let body = obligation.cause.body_id; diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 52f099e77255b..e2dc87061348e 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -204,12 +204,12 @@ impl Global { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), + 0 => Ok(layout.dangling_ptr().cast_slice(0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) }; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, size)) + Ok(ptr.cast_slice(size)) }, } } @@ -261,7 +261,7 @@ impl Global { if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + Ok(ptr.cast_slice(new_size)) }, // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, @@ -297,7 +297,7 @@ impl Global { // SAFETY: conditions must be upheld by the caller 0 => unsafe { self.deallocate(ptr, old_layout); - Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0)) + Ok(new_layout.dangling_ptr().cast_slice(0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller @@ -307,7 +307,7 @@ impl Global { let raw_ptr = realloc_nonnull(ptr, old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + Ok(ptr.cast_slice(new_size)) }, // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, @@ -388,7 +388,7 @@ impl Global { #[rustc_const_unstable(feature = "const_heap", issue = "79597")] const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), + 0 => Ok(layout.dangling_ptr().cast_slice(0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); @@ -397,7 +397,7 @@ impl Global { // SAFETY: the pointer returned by `const_allocate` is valid to write to. ptr.write_bytes(0, size); } - Ok(NonNull::slice_from_raw_parts(ptr, size)) + Ok(ptr.cast_slice(size)) }, } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index d91b35c1f6077..5a900db9d1ce8 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -226,9 +226,7 @@ impl VecDeque { /// `range` must lie inside `0..self.capacity()`. #[inline] unsafe fn buffer_range(&self, range: Range) -> *mut [T] { - unsafe { - ptr::slice_from_raw_parts_mut(self.ptr().add(range.start), range.end - range.start) - } + unsafe { self.ptr().add(range.start).cast_slice(range.end - range.start) } } /// Returns `true` if the buffer is at full capacity. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5fe5464ab2cdd..3f0c0ab3080c5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,6 +140,7 @@ #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] #![feature(ptr_alignment_type)] +#![feature(ptr_cast_slice)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(rev_into_inner)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 0309d63cce06d..2f7d26c7a9724 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -244,7 +244,7 @@ impl RawVec { let me = ManuallyDrop::new(self); unsafe { - let slice = ptr::slice_from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + let slice = me.ptr().cast::>().cast_slice(len); Box::from_raw_in(slice, ptr::read(&me.inner.alloc)) } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2491489517688..523c9b8b15858 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1160,10 +1160,7 @@ impl Rc<[T]> { Rc::from_ptr(Rc::allocate_for_layout( Layout::array::(len).unwrap(), |layout| Global.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, + |mem| mem.cast::().cast_slice(len) as *mut RcInner<[mem::MaybeUninit]>, )) } } @@ -1231,10 +1228,7 @@ impl Rc<[T], A> { Rc::allocate_for_layout( Layout::array::(len).unwrap(), |layout| alloc.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut RcInner<[mem::MaybeUninit]> - }, + |mem| mem.cast::().cast_slice(len) as *mut RcInner<[mem::MaybeUninit]>, ), alloc, ) @@ -2327,7 +2321,7 @@ impl Rc<[T]> { Self::allocate_for_layout( Layout::array::(len).unwrap(), |layout| Global.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + |mem| mem.cast::().cast_slice(len) as *mut RcInner<[T]>, ) } } @@ -2404,7 +2398,7 @@ impl Rc<[T], A> { Rc::<[T]>::allocate_for_layout( Layout::array::(len).unwrap(), |layout| alloc.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut RcInner<[T]>, + |mem| mem.cast::().cast_slice(len) as *mut RcInner<[T]>, ) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 597d26d3239ad..4a9878d8e249d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1306,10 +1306,7 @@ impl Arc<[T]> { Arc::from_ptr(Arc::allocate_for_layout( Layout::array::(len).unwrap(), |layout| Global.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) - as *mut ArcInner<[mem::MaybeUninit]> - }, + |mem| mem.cast::().cast_slice(len) as *mut ArcInner<[mem::MaybeUninit]>, )) } } @@ -1378,10 +1375,7 @@ impl Arc<[T], A> { Arc::allocate_for_layout( Layout::array::(len).unwrap(), |layout| alloc.allocate_zeroed(layout), - |mem| { - ptr::slice_from_raw_parts_mut(mem.cast::(), len) - as *mut ArcInner<[mem::MaybeUninit]> - }, + |mem| mem.cast::().cast_slice(len) as *mut ArcInner<[mem::MaybeUninit]>, ), alloc, ) @@ -2272,7 +2266,7 @@ impl Arc<[T]> { Self::allocate_for_layout( Layout::array::(len).unwrap(), |layout| Global.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut ArcInner<[T]>, + |mem| mem.cast::().cast_slice(len) as *mut ArcInner<[T]>, ) } } @@ -2351,7 +2345,7 @@ impl Arc<[T], A> { Arc::allocate_for_layout( Layout::array::(len).unwrap(), |layout| alloc.allocate(layout), - |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut ArcInner<[T]>, + |mem| mem.cast::().cast_slice(len) as *mut ArcInner<[T]>, ) } } diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index 9a6bfa823f2a5..d12dea20b33cb 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -232,7 +232,7 @@ impl Drop for Drain<'_, T, A> { // invalidate raw pointers to it which some unsafe code might rely on. let vec_ptr = vec.as_mut().as_mut_ptr(); let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr); - let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); + let to_drop = vec_ptr.add(drop_offset).cast_slice(drop_len); ptr::drop_in_place(to_drop); } } diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index c8cc758ac15c4..5c3d598cdef0c 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use core::ptr::{self, NonNull, drop_in_place}; +use core::ptr::NonNull; use crate::alloc::Global; use crate::raw_vec::RawVec; @@ -20,9 +20,7 @@ impl InPlaceDrop { impl Drop for InPlaceDrop { #[inline] fn drop(&mut self) { - unsafe { - ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.inner, self.len())); - } + unsafe { self.inner.cast_slice(self.len()).drop_in_place() } } } @@ -42,7 +40,7 @@ impl Drop for InPlaceDstDataSrcBufDrop { unsafe { let _drop_allocation = RawVec::::from_nonnull_in(self.ptr.cast::(), self.src_cap, Global); - drop_in_place(core::ptr::slice_from_raw_parts_mut::(self.ptr.as_ptr(), self.len)); + self.ptr.as_ptr().cast_slice(self.len).drop_in_place(); }; } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 9c4b24b2731b1..97e4912596b94 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -115,7 +115,7 @@ impl IntoIter { } fn as_raw_mut_slice(&mut self) -> *mut [T] { - ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len()) + self.ptr.as_ptr().cast_slice(self.len()) } /// Drops remaining elements and relinquishes the backing allocation. @@ -282,7 +282,7 @@ impl Iterator for IntoIter { #[inline] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { let step_size = self.len().min(n); - let to_drop = ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), step_size); + let to_drop = self.ptr.as_ptr().cast_slice(step_size); if T::IS_ZST { // See `next` for why we sub `end` here. self.end = self.end.wrapping_byte_sub(step_size); @@ -457,9 +457,9 @@ impl DoubleEndedIterator for IntoIter { } let to_drop = if T::IS_ZST { // ZST may cause unalignment - ptr::slice_from_raw_parts_mut(ptr::NonNull::::dangling().as_ptr(), step_size) + ptr::NonNull::::dangling().as_ptr().cast_slice(step_size) } else { - ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size) + self.end.cast::().cast_mut().cast_slice(step_size) }; // SAFETY: same as for advance_by() unsafe { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d2b7837d98fa6..130f72b0ee485 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1830,7 +1830,7 @@ impl Vec { return; } let remaining_len = self.len - len; - let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); + let s = self.as_mut_ptr().add(len).cast_slice(remaining_len); self.len = len; ptr::drop_in_place(s); } @@ -4289,7 +4289,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { // use drop for [T] // use a raw slice to refer to the elements of the vector as weakest necessary type; // could avoid questions of validity in certain cases - ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len)) + self.as_mut_ptr().cast_slice(self.len).drop_in_place() } // RawVec handles deallocation } diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 936d60fdad73b..db643ccb7a4e6 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -36,6 +36,7 @@ #![feature(iter_next_chunk)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(ptr_alignment_type)] +#![feature(ptr_cast_slice)] #![feature(ptr_internals)] #![feature(rev_into_inner)] #![feature(sized_type_properties)] diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs index a56204187c0a0..4b4d1787ace63 100644 --- a/library/alloctests/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -107,7 +107,7 @@ fn eq_unsized() { fn eq_unsized_slice() { let a: Arc<[()]> = Arc::new([(); 3]); let ptr: *const () = Arc::into_raw(a.clone()).cast(); - let b: Arc<[()]> = unsafe { Arc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) }; + let b: Arc<[()]> = unsafe { Arc::from_raw(ptr.cast_slice(42)) }; assert!(a == a); assert!(!(a != a)); assert!(a != b); diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs index 83fd1ef7449a3..a0c3cb55edcc6 100644 --- a/library/alloctests/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs @@ -104,7 +104,7 @@ pub struct ConstAllocator; unsafe impl Allocator for ConstAllocator { fn allocate(&self, layout: Layout) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), + 0 => Ok(layout.dangling_ptr().cast_slice(0)), _ => unsafe { let ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8])) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 699a5010282b0..1414835058b9a 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] #![feature(vec_try_remove)] +#![feature(ptr_cast_slice)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs index 5be0e8f339119..0417206d713ef 100644 --- a/library/alloctests/tests/rc.rs +++ b/library/alloctests/tests/rc.rs @@ -108,7 +108,7 @@ fn eq_unsized() { fn eq_unsized_slice() { let a: Rc<[()]> = Rc::new([(); 3]); let ptr: *const () = Rc::into_raw(a.clone()).cast(); - let b: Rc<[()]> = unsafe { Rc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) }; + let b: Rc<[()]> = unsafe { Rc::from_raw(ptr.cast_slice(42)) }; assert!(a == a); assert!(!(a != a)); assert!(a != b); diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index d85d2e44cd2ba..54bdc4c19cfae 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2569,7 +2569,7 @@ fn test_box_zero_allocator() { } else { unsafe { std::alloc::alloc(layout) } }; - Ok(NonNull::slice_from_raw_parts(NonNull::new(ptr).ok_or(AllocError)?, layout.size())) + Ok(NonNull::new(ptr).ok_or(AllocError)?.cast_slice(layout.size())) } unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index 5d96de5cbcb6b..bcda315f7a4a0 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -218,10 +218,8 @@ impl Drop for Buffer { // SAFETY: our invariant guarantees that N elements starting from // `self.start` are initialized. We drop them here. unsafe { - let initialized_part: *mut [T] = crate::ptr::slice_from_raw_parts_mut( - self.buffer_mut_ptr().add(self.start).cast(), - N, - ); + let initialized_part: *mut [T] = + self.buffer_mut_ptr().add(self.start).cast::().cast_slice(N); ptr::drop_in_place(initialized_part); } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index acc758a75e77b..b16996acb1c44 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -234,6 +234,10 @@ pub mod autodiff { pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse}; } +#[unstable(feature = "gpu_offload", issue = "131513")] +#[doc = include_str!("../../core/src/offload.md")] +pub mod offload; + #[unstable(feature = "contracts", issue = "128044")] pub mod contracts; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6d7923baa175f..c21191dbc19be 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1628,6 +1628,48 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// The `offload_kernel` macro is applied to a function to generate two separate + /// definitions: a host-side wrapper for dispatch and a device-side kernel. + /// + /// The macro does not perform the offload itself. It generates the necessary + /// code required by the compiler's offloading infrastructure. + /// + /// ### Usage example: + /// + /// ```rust,ignore (offload requires a -Z flag) + /// #[offload_kernel] + /// fn foo(a: &[f32], b: &[f32], c: *mut f32) { + /// *c = a[0] + b[0]; + /// } + /// ``` + /// + /// This expands to the host-side function: + /// + /// ```rust,ignore (offload requires a -Z flag) + /// #[unsafe(no_mangle)] + /// #[inline(never)] + /// fn foo(_: &[f32], _: &[f32], _: *mut f32) { + /// ::core::panicking::panic("not implemented") + /// } + /// ``` + /// + /// And the device-side kernel: + /// + /// ```rust,ignore (offload requires a -Z flag) + /// #[rustc_offload_kernel] + /// #[unsafe(no_mangle)] + /// unsafe extern "gpu-kernel" fn foo(a: &[f32], b: &[f32], c: *mut f32) { + /// *c = a[0] + b[0]; + /// } + /// ``` + #[unstable(feature = "gpu_offload", issue = "131513")] + #[allow_internal_unstable(rustc_attrs)] + #[allow_internal_unstable(core_intrinsics)] + #[rustc_builtin_macro] + pub macro offload_kernel($item:item) { + /* compiler built-in */ + } + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be diff --git a/library/core/src/offload.md b/library/core/src/offload.md new file mode 100644 index 0000000000000..fb3c0b87b4815 --- /dev/null +++ b/library/core/src/offload.md @@ -0,0 +1,39 @@ +This module provides support for gpu offloading. For technical details regarding the `offload_kernel` +and how to use it, see their respective documentation. + +## General usage +The `offload_kernel` macro can be applied to a function to generate the necessary code to launch a +kernel on the target device. + +```rust,ignore (optional component) +#[offload_kernel] +fn kernel(x: *mut [f64; 256]) { + // SAFETY: + // calling our `arch` functions and dereferencing a raw pointer is unsafe + unsafe { + let n = (*x).len(); + let i = (thread_idx_x() + block_idx_x() * block_dim_x()) as usize; + if i < n { + (*x)[i] = i as f64; + } + } +} +``` + +To launch an offloaded kernel, the only current way is to use the `core::intrinsic::offload` +intrinsic (note that intrinsics usage is discouraged outside the standard library). This +allows you to specify grid and block dimensions and pass the required arguments to the device. + +```rust,ignore (optional component) +let mut x = [0.0f64; 256]; +core::intrinsics::offload::<_, _, ()>(kernel, [256, 1, 1], [1, 1, 1], (&mut x as *mut [f64; 256],)); +``` + +For precise information on the `offload` intrinsic, see its respective documentation. + +## Current limitations: + +- Usage is restricted to types supported by the current device-mapping implementation. +- Generics and functions accepting dyn Trait are not supported. +- Kernel execution is currently restricted to intrinsics usage, which is discouraged outside of the +standard library. diff --git a/library/core/src/offload/mod.rs b/library/core/src/offload/mod.rs new file mode 100644 index 0000000000000..164bbb9f0047d --- /dev/null +++ b/library/core/src/offload/mod.rs @@ -0,0 +1,5 @@ +// offload module +#[unstable(feature = "gpu_offload", issue = "131513")] +pub use crate::macros::builtin::offload_kernel; +#[unstable(feature = "gpu_offload", issue = "131513")] +pub use crate::offload; diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8b7b08bf82317..5cbbebf9f4788 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1400,11 +1400,11 @@ impl *const T { /// /// ```rust /// #![feature(ptr_cast_slice)] + /// /// // create a slice pointer when starting out with a pointer to the first element /// let x = [5, 6, 7]; - /// let raw_pointer = x.as_ptr(); - /// let slice = raw_pointer.cast_slice(3); - /// assert_eq!(unsafe { &*slice }[2], 7); + /// let raw_slice = x.as_ptr().cast_slice(3); + /// assert_eq!(unsafe { &*raw_slice }[2], 7); /// ``` /// /// You must ensure that the pointer is valid and not null before dereferencing diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 98b70a77fad7b..53ef7f754d201 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1675,13 +1675,13 @@ impl *mut T { /// #![feature(ptr_cast_slice)] /// /// let x = &mut [5, 6, 7]; - /// let slice = x.as_mut_ptr().cast_slice(3); + /// let raw_mut_slice = x.as_mut_ptr().cast_slice(3); /// /// unsafe { - /// (*slice)[2] = 99; // assign a value at an index in the slice + /// (*raw_mut_slice)[2] = 99; // assign a value at an index in the slice /// }; /// - /// assert_eq!(unsafe { &*slice }[2], 99); + /// assert_eq!(unsafe { &*raw_mut_slice }[2], 99); /// ``` /// /// You must ensure that the pointer is valid and not null before dereferencing @@ -1701,6 +1701,7 @@ impl *mut T { slice_from_raw_parts_mut(self, len) } } + impl *mut MaybeUninit { /// Casts from a maybe-uninitialized type to its initialized version. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index b9b42c1efe05a..f165e235611b8 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1444,7 +1444,7 @@ impl NonNull<[T]> { #[inline] pub const fn slice_from_raw_parts(data: NonNull, len: usize) -> Self { // SAFETY: `data` is a `NonNull` pointer which is necessarily non-null - unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) } + unsafe { Self::new_unchecked(data.as_ptr().cast_slice(len)) } } /// Returns the length of a non-null raw slice. diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 3b5cec22b69ea..096c847c3b8e2 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -5,7 +5,7 @@ use crate::cmp::Ordering; use crate::intrinsics::unchecked_sub; use crate::slice::SliceIndex; use crate::ub_checks::assert_unsafe_precondition; -use crate::{ops, ptr, range}; +use crate::{ops, range}; /// Implements ordering of strings. /// @@ -209,7 +209,7 @@ unsafe impl const SliceIndex for ops::Range { // which satisfies all the conditions for `add`. unsafe { let new_len = unchecked_sub(self.end, self.start); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str + slice.as_ptr().add(self.start).cast_slice(new_len) as *const str } } #[inline] @@ -230,7 +230,7 @@ unsafe impl const SliceIndex for ops::Range { // SAFETY: see comments for `get_unchecked`. unsafe { let new_len = unchecked_sub(self.end, self.start); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str + slice.as_mut_ptr().add(self.start).cast_slice(new_len) as *mut str } } #[inline] @@ -314,7 +314,7 @@ unsafe impl const SliceIndex for range::Range { // which satisfies all the conditions for `add`. unsafe { let new_len = unchecked_sub(self.end, self.start); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str + slice.as_ptr().add(self.start).cast_slice(new_len) as *const str } } #[inline] @@ -335,7 +335,7 @@ unsafe impl const SliceIndex for range::Range { // SAFETY: see comments for `get_unchecked`. unsafe { let new_len = unchecked_sub(self.end, self.start); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str + slice.as_mut_ptr().add(self.start).cast_slice(new_len) as *mut str } } #[inline] diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index ed0322e2cf5d0..7a576e083df7c 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -142,7 +142,7 @@ impl System { #[inline] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), + 0 => Ok(layout.dangling_ptr().cast_slice(0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { @@ -151,7 +151,7 @@ impl System { GlobalAlloc::alloc(self, layout) }; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, size)) + Ok(ptr.cast_slice(size)) }, } } @@ -187,7 +187,7 @@ impl System { if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + Ok(ptr.cast_slice(new_size)) }, // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, @@ -266,7 +266,7 @@ unsafe impl Allocator for System { // SAFETY: conditions must be upheld by the caller 0 => unsafe { Allocator::deallocate(self, ptr, old_layout); - Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0)) + Ok(new_layout.dangling_ptr().cast_slice(0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller @@ -276,7 +276,7 @@ unsafe impl Allocator for System { let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + Ok(ptr.cast_slice(new_size)) }, // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 150ce9c1b9a96..a4a5e8561dfcf 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -220,14 +220,13 @@ impl fmt::Debug for VarsOs { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn var>(key: K) -> Result { - _var(key.as_ref()) -} - -fn _var(key: &OsStr) -> Result { - match var_os(key) { - Some(s) => s.into_string().map_err(VarError::NotUnicode), - None => Err(VarError::NotPresent), + fn inner(key: &OsStr) -> Result { + env_imp::getenv(key) + .ok_or(VarError::NotPresent)? + .into_string() + .map_err(VarError::NotUnicode) } + inner(key.as_ref()) } /// Fetches the environment variable `key` from the current process, returning @@ -257,11 +256,7 @@ fn _var(key: &OsStr) -> Result { #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn var_os>(key: K) -> Option { - _var_os(key.as_ref()) -} - -fn _var_os(key: &OsStr) -> Option { - env_imp::getenv(key) + env_imp::getenv(key.as_ref()) } /// The error type for operations interacting with environment variables. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9c47f0ea35e8f..8086cab34cf44 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -289,6 +289,7 @@ #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] +#![feature(gpu_offload)] #![feature(intra_doc_pointers)] #![feature(lang_items)] #![feature(link_cfg)] @@ -366,6 +367,7 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_as_uninit)] +#![feature(ptr_cast_slice)] #![feature(ptr_mask)] #![feature(random)] #![feature(raw_os_error_ty)] @@ -662,6 +664,12 @@ pub mod autodiff { pub use core::autodiff::{autodiff_forward, autodiff_reverse}; } +#[unstable(feature = "gpu_offload", issue = "131513")] +#[doc = include_str!("../../core/src/offload.md")] +pub mod offload { + pub use core::offload::{offload, offload_kernel}; +} + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. diff --git a/library/std/src/net/test.rs b/library/std/src/net/test.rs index 68cbf7b669232..5002bb5c8e083 100644 --- a/library/std/src/net/test.rs +++ b/library/std/src/net/test.rs @@ -4,9 +4,6 @@ use crate::env; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use crate::sync::atomic::{AtomicUsize, Ordering}; -static PORT: AtomicUsize = AtomicUsize::new(0); -const BASE_PORT: u16 = 19600; - /// A localhost address whose port will be picked automatically by the OS. pub const LOCALHOST_IP4: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0)); @@ -14,16 +11,6 @@ pub const LOCALHOST_IP4: SocketAddr = pub const LOCALHOST_IP6: SocketAddr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 0, 0, 0)); -pub fn next_test_ip4() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; - SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) -} - -pub fn next_test_ip6() -> SocketAddr { - let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + BASE_PORT; - SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0)) -} - pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { SocketAddr::V4(SocketAddrV4::new(a, p)) } diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 0638b36c54f9d..ede0240fbda57 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -1,15 +1,10 @@ use crate::io::ErrorKind; -use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6}; +use crate::net::test::{LOCALHOST_IP4, LOCALHOST_IP6, compare_ignore_zoneid}; use crate::net::*; use crate::sync::mpsc::channel; use crate::thread; use crate::time::{Duration, Instant}; -fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { - f(next_test_ip4(), next_test_ip4()); - f(next_test_ip6(), next_test_ip6()); -} - macro_rules! t { ($e:expr) => { match $e { @@ -19,6 +14,11 @@ macro_rules! t { }; } +fn each_ip(f: &mut dyn FnMut(UdpSocket, UdpSocket)) { + f(t!(UdpSocket::bind(LOCALHOST_IP4)), t!(UdpSocket::bind(LOCALHOST_IP4))); + f(t!(UdpSocket::bind(LOCALHOST_IP6)), t!(UdpSocket::bind(LOCALHOST_IP6))); +} + #[test] fn bind_error() { match UdpSocket::bind("1.1.1.1:9999") { @@ -30,18 +30,19 @@ fn bind_error() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // no threads fn socket_smoke_test_ip4() { - each_ip(&mut |server_ip, client_ip| { + each_ip(&mut |server, client| { + let server_ip = t!(server.local_addr()); + let client_ip = t!(client.local_addr()); + let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); let _t = thread::spawn(move || { - let client = t!(UdpSocket::bind(&client_ip)); rx1.recv().unwrap(); t!(client.send_to(&[99], &server_ip)); tx2.send(()).unwrap(); }); - let server = t!(UdpSocket::bind(&server_ip)); tx1.send(()).unwrap(); let mut buf = [0]; let (nread, src) = t!(server.recv_from(&mut buf)); @@ -53,29 +54,28 @@ fn socket_smoke_test_ip4() { } #[test] -fn socket_name() { - each_ip(&mut |addr, _| { - let server = t!(UdpSocket::bind(&addr)); - assert_eq!(addr, t!(server.local_addr())); - }) -} +fn socket_and_peer_name() { + each_ip(&mut |sock1, sock2| { + let addr1 = t!(sock1.local_addr()); + let addr2 = t!(sock2.local_addr()); -#[test] -fn socket_peer() { - each_ip(&mut |addr1, addr2| { - let server = t!(UdpSocket::bind(&addr1)); - assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); - t!(server.connect(&addr2)); - assert_eq!(addr2, t!(server.peer_addr())); + assert_eq!(sock1.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); + assert!(addr1.ip() == LOCALHOST_IP4.ip() || addr1.ip() == LOCALHOST_IP6.ip()); + + t!(sock1.connect(addr2)); + t!(sock2.connect(addr1)); + + assert_eq!(addr2, t!(sock1.peer_addr())); + assert_eq!(addr1, t!(sock2.peer_addr())); }) } #[test] #[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_smoke() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); + each_ip(&mut |sock1, sock2| { + let addr1 = t!(sock1.local_addr()); + let addr2 = t!(sock2.local_addr()); let _t = thread::spawn(move || { let mut buf = [0, 0]; @@ -107,9 +107,9 @@ fn udp_clone_smoke() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_two_read() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); + each_ip(&mut |sock1, sock2| { + let addr1 = t!(sock1.local_addr()); + let (tx1, rx) = channel(); let tx2 = tx1.clone(); @@ -140,9 +140,8 @@ fn udp_clone_two_read() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_two_write() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); + each_ip(&mut |sock1, sock2| { + let addr2 = t!(sock2.local_addr()); let (tx, rx) = channel(); let (serv_tx, serv_rx) = channel(); @@ -177,9 +176,9 @@ fn udp_clone_two_write() { #[test] fn debug() { let name = if cfg!(windows) { "socket" } else { "fd" }; - let socket_addr = next_test_ip4(); - let udpsock = t!(UdpSocket::bind(&socket_addr)); + let udpsock = t!(UdpSocket::bind(LOCALHOST_IP4)); + let socket_addr = t!(udpsock.local_addr()); let udpsock_inner = udpsock.0.socket().as_raw(); let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}"); assert_eq!(format!("{udpsock:?}"), compare); @@ -195,9 +194,7 @@ fn debug() { #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported #[test] fn timeouts() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); + let stream = t!(UdpSocket::bind(LOCALHOST_IP4)); let dur = Duration::new(15410, 0); assert_eq!(None, t!(stream.read_timeout())); @@ -220,9 +217,7 @@ fn timeouts() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); + let stream = t!(UdpSocket::bind(LOCALHOST_IP4)); t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); let mut buf = [0; 10]; @@ -245,9 +240,8 @@ fn test_read_timeout() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_with_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); + let stream = t!(UdpSocket::bind(LOCALHOST_IP4)); + let addr = t!(stream.local_addr()); t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); t!(stream.send_to(b"hello world", &addr)); @@ -275,9 +269,7 @@ fn test_read_with_timeout() { // when passed zero Durations #[test] fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); + let socket = t!(UdpSocket::bind(LOCALHOST_IP4)); let result = socket.set_write_timeout(Some(Duration::new(0, 0))); let err = result.unwrap_err(); @@ -290,9 +282,8 @@ fn test_timeout_zero_duration() { #[test] fn connect_send_recv() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); + let socket = t!(UdpSocket::bind(LOCALHOST_IP4)); + let addr = t!(socket.local_addr()); t!(socket.connect(addr)); t!(socket.send(b"hello world")); @@ -305,8 +296,8 @@ fn connect_send_recv() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // peek not supported fn connect_send_peek_recv() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); + each_ip(&mut |socket, _| { + let addr = t!(socket.local_addr()); t!(socket.connect(addr)); t!(socket.send(b"hello world")); @@ -328,8 +319,8 @@ fn connect_send_peek_recv() { #[test] #[cfg_attr(target_os = "wasi", ignore)] // peek_from not supported fn peek_from() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); + each_ip(&mut |socket, _| { + let addr = t!(socket.local_addr()); t!(socket.send_to(b"hello world", &addr)); for _ in 1..3 { @@ -350,9 +341,7 @@ fn peek_from() { fn ttl() { let ttl = 100; - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); + let stream = t!(UdpSocket::bind(LOCALHOST_IP4)); t!(stream.set_ttl(ttl)); assert_eq!(ttl, t!(stream.ttl())); @@ -360,8 +349,8 @@ fn ttl() { #[test] fn set_nonblocking() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); + each_ip(&mut |socket, _| { + let addr = t!(socket.local_addr()); t!(socket.set_nonblocking(true)); t!(socket.set_nonblocking(false)); diff --git a/library/std/src/os/net/linux_ext/tests.rs b/library/std/src/os/net/linux_ext/tests.rs index 0758b426ccc59..02839ee6a2aad 100644 --- a/library/std/src/os/net/linux_ext/tests.rs +++ b/library/std/src/os/net/linux_ext/tests.rs @@ -1,6 +1,6 @@ #[test] fn quickack() { - use crate::net::test::next_test_ip4; + use crate::net::test::LOCALHOST_IP4; use crate::net::{TcpListener, TcpStream}; use crate::os::net::linux_ext::tcp::TcpStreamExt; @@ -13,8 +13,8 @@ fn quickack() { }; } - let addr = next_test_ip4(); - let _listener = t!(TcpListener::bind(&addr)); + let listener = t!(TcpListener::bind(LOCALHOST_IP4)); + let addr = t!(listener.local_addr()); let stream = t!(TcpStream::connect(&("localhost", addr.port()))); @@ -29,7 +29,7 @@ fn quickack() { #[test] #[cfg(target_os = "linux")] fn deferaccept() { - use crate::net::test::next_test_ip4; + use crate::net::test::LOCALHOST_IP4; use crate::net::{TcpListener, TcpStream}; use crate::os::net::linux_ext::tcp::TcpStreamExt; use crate::time::Duration; @@ -43,10 +43,11 @@ fn deferaccept() { }; } - let addr = next_test_ip4(); let one = Duration::from_secs(1u64); let zero = Duration::from_secs(0u64); - let _listener = t!(TcpListener::bind(&addr)); + + let listener = t!(TcpListener::bind(LOCALHOST_IP4)); + let addr = t!(listener.local_addr()); let stream = t!(TcpStream::connect(&("localhost", addr.port()))); stream.set_deferaccept(one).expect("set_deferaccept failed"); assert_eq!(stream.deferaccept().unwrap(), one); diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index c2694316249a3..f4115ca6124a7 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -151,7 +151,7 @@ unsafe impl UserSafe for [T] { let elem_size = size_of::(); assert_eq!(size % elem_size, 0); let len = size / elem_size; - ptr::slice_from_raw_parts_mut(ptr as _, len) + ptr.cast::().cast_slice(len) } } diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 528bc2be2244a..e0c4fa579275a 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -27,11 +27,13 @@ pub struct Command { env: CommandEnv, } -#[derive(Copy, Clone, Debug)] +#[derive(Debug)] pub enum Stdio { Inherit, Null, MakePipe, + #[allow(dead_code)] // This variant exists only for the Debug impl + InheritFile(File), } impl Command { @@ -120,6 +122,7 @@ impl Command { ) } .map(Some), + Stdio::InheritFile(_) => Err(unsupported()?), Stdio::Inherit => Ok(None), } } @@ -135,6 +138,7 @@ impl Command { ) } .map(Some), + Stdio::InheritFile(_) => Err(unsupported()?), Stdio::Inherit => Ok(None), Stdio::MakePipe => unsupported(), } @@ -153,7 +157,7 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec } // Setup Stdout - let stdout = command.stdout.unwrap_or(Stdio::MakePipe); + let stdout = command.stdout.take().unwrap_or(Stdio::MakePipe); let stdout = Command::create_pipe(stdout)?; if let Some(con) = stdout { cmd.stdout_init(con) @@ -162,7 +166,7 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec }; // Setup Stderr - let stderr = command.stderr.unwrap_or(Stdio::MakePipe); + let stderr = command.stderr.take().unwrap_or(Stdio::MakePipe); let stderr = Command::create_pipe(stderr)?; if let Some(con) = stderr { cmd.stderr_init(con) @@ -171,7 +175,7 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec }; // Setup Stdin - let stdin = command.stdin.unwrap_or(Stdio::Null); + let stdin = command.stdin.take().unwrap_or(Stdio::Null); let stdin = Command::create_stdin(stdin)?; if let Some(con) = stdin { cmd.stdin_init(con) @@ -217,25 +221,19 @@ impl From for Stdio { impl From for Stdio { fn from(_: io::Stdout) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::Inherit } } impl From for Stdio { fn from(_: io::Stderr) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::Inherit } } impl From for Stdio { - fn from(_file: File) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + fn from(file: File) -> Stdio { + Stdio::InheritFile(file) } } @@ -642,7 +640,7 @@ mod uefi_command_internal { } if let Some((ptr, len)) = self.args { - let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + let _ = unsafe { Box::from_raw(ptr.cast_slice(len)) }; } } } diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index c7ce2ded42e97..6d406ec4cc73b 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -6,73 +6,50 @@ We currently work on launching the following Rust kernel on the GPU. To follow along, copy it to a `src/lib.rs` file. ```rust -#![feature(abi_gpu_kernel)] -#![feature(rustc_attrs)] -#![feature(core_intrinsics)] +#![allow(internal_features)] +#![feature(gpu_offload)] +#![cfg_attr(target_os = "linux", feature(core_intrinsics))] +#![cfg_attr(target_arch = "amdgpu", feature(stdarch_amdgpu, abi_gpu_kernel))] +#![cfg_attr(target_arch = "nvptx64", feature(stdarch_nvptx, abi_gpu_kernel))] #![no_std] #[cfg(target_os = "linux")] extern crate libc; -#[cfg(target_os = "linux")] -use libc::c_char; -#[cfg(target_os = "linux")] -use core::mem; +use core::offload::offload_kernel; #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } -#[cfg(target_os = "linux")] -#[unsafe(no_mangle)] -#[inline(never)] -fn main() { - let array_c: *mut [f64; 256] = - unsafe { libc::calloc(256, (mem::size_of::()) as libc::size_t) as *mut [f64; 256] }; - let output = c"The first element is zero %f\n"; - let output2 = c"The first element is NOT zero %f\n"; - let output3 = c"The second element is %f\n"; - unsafe { - let val: *const c_char = if (*array_c)[0] < 0.1 { - output.as_ptr() - } else { - output2.as_ptr() - }; - libc::printf(val, (*array_c)[0]); - } +#[cfg(target_arch = "amdgpu")] +use core::arch::amdgpu::{workgroup_id_x as block_idx_x, workitem_id_x as thread_idx_x}; +#[cfg(target_arch = "nvptx64")] +use core::arch::nvptx::{ + _block_dim_x as block_dim_x, _block_idx_x as block_idx_x, _thread_idx_x as thread_idx_x, +}; +#[offload_kernel] +fn kernel(x: *mut [f64; 256]) { unsafe { - kernel(array_c); + let n = (*x).len(); + let i = (thread_idx_x() + block_idx_x() * block_dim_x()) as usize; + if i < n { + (*x)[i] = i as f64; + } } - core::hint::black_box(&array_c); - unsafe { - let val: *const c_char = if (*array_c)[0] < 0.1 { - output.as_ptr() - } else { - output2.as_ptr() - }; - libc::printf(val, (*array_c)[0]); - libc::printf(output3.as_ptr(), (*array_c)[1]); - } -} - -#[inline(never)] -unsafe fn kernel(x: *mut [f64; 256]) { - core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) } #[cfg(target_os = "linux")] -unsafe extern "C" { - pub fn kernel_1(array_b: *mut [f64; 256]); -} - -#[cfg(not(target_os = "linux"))] #[unsafe(no_mangle)] -#[inline(never)] -#[rustc_offload_kernel] -pub extern "gpu-kernel" fn kernel_1(x: *mut [f64; 256]) { - unsafe { (*x)[0] = 21.0 }; +fn main() { + let mut x = [0.0f64; 256]; + core::intrinsics::offload::<_, _, ()>(kernel, [256, 1, 1], [1, 1, 1], (&mut x as *mut [f64; 256],)); + for i in 0..x.len() { + assert_eq!(x[i], i as f64); + } + unsafe { libc::printf(c"all checks passed".as_ptr()); } } ``` @@ -96,7 +73,7 @@ This call also does a lot of work and generates multiple intermediate files for While we integrated most offload steps into rustc by now, one binary invocation still remains for now: ``` -"clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "target//release/host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" +"clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "main" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "target//release/host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" ``` You can try to find the paths to those files on your system. @@ -112,9 +89,7 @@ In the final step, you can now run your binary ``` ./main -The first element is zero 0.000000 -The first element is NOT zero 21.000000 -The second element is 0.000000 +all checks passed! ``` To receive more information about the memory transfer, you can enable info printing with diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index c5875e88fd3c4..8b303fe1c87d9 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -36,24 +36,28 @@ + } + } + } -+ scope 13 (inlined slice_from_raw_parts_mut::) { -+ scope 14 (inlined std::ptr::from_raw_parts_mut::<[A], A>) { ++ scope 13 (inlined std::ptr::mut_ptr::::cast_slice) { ++ scope 14 (inlined slice_from_raw_parts_mut::) { ++ scope 15 (inlined std::ptr::from_raw_parts_mut::<[A], A>) { ++ } + } + } -+ scope 15 (inlined drop_in_place::<[A]>) { -+ let mut _13: &mut [A]; -+ scope 16 (inlined std::ptr::drop_glue::<[A]> - shim(Some([A]))) { -+ let mut _14: usize; -+ let mut _15: *mut A; -+ let mut _16: bool; ++ scope 16 (inlined std::ptr::mut_ptr::::drop_in_place) { ++ scope 17 (inlined drop_in_place::<[A]>) { ++ let mut _13: &mut [A]; ++ scope 18 (inlined std::ptr::drop_glue::<[A]> - shim(Some([A]))) { ++ let mut _14: usize; ++ let mut _15: *mut A; ++ let mut _16: bool; ++ } + } + } + } + } + } -+ scope 17 (inlined drop_in_place::>) { ++ scope 19 (inlined drop_in_place::>) { + let mut _17: &mut std::option::Option; -+ scope 18 (inlined std::ptr::drop_glue::> - shim(Some(Option))) { ++ scope 20 (inlined std::ptr::drop_glue::> - shim(Some(Option))) { + let mut _18: isize; + let mut _19: isize; + } diff --git a/tests/pretty/offload/offload_kernel.device.pp b/tests/pretty/offload/offload_kernel.device.pp new file mode 100644 index 0000000000000..9c8e6edaf2ed3 --- /dev/null +++ b/tests/pretty/offload/offload_kernel.device.pp @@ -0,0 +1,26 @@ +#![feature(prelude_import)] +#![no_std] +//@ only-nightly +//@ revisions: host device + +//@ pretty-mode:expanded +//@ pretty-compare-only +//@[host] pp-exact:offload_kernel.host.pp +//@[device] pp-exact:offload_kernel.device.pp + +//@[device] compile-flags: -Zunstable-options -Zoffload=Device + +#![feature(gpu_offload)] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +use std::offload::offload_kernel; + +#[rustc_offload_kernel] +#[unsafe(no_mangle)] +unsafe extern "gpu-kernel" fn foo(a: &[f32], b: &[f32], c: *mut f32) { + *c = a[0] + b[0]; +} + +fn main() {} diff --git a/tests/pretty/offload/offload_kernel.host.pp b/tests/pretty/offload/offload_kernel.host.pp new file mode 100644 index 0000000000000..cf60ee9f8138b --- /dev/null +++ b/tests/pretty/offload/offload_kernel.host.pp @@ -0,0 +1,26 @@ +#![feature(prelude_import)] +#![no_std] +//@ only-nightly +//@ revisions: host device + +//@ pretty-mode:expanded +//@ pretty-compare-only +//@[host] pp-exact:offload_kernel.host.pp +//@[device] pp-exact:offload_kernel.device.pp + +//@[device] compile-flags: -Zunstable-options -Zoffload=Device + +#![feature(gpu_offload)] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +use std::offload::offload_kernel; + +#[unsafe(no_mangle)] +#[inline(never)] +fn foo(_: &[f32], _: &[f32], _: *mut f32) { + + ::core::panicking::panic("not implemented") +} +fn main() {} diff --git a/tests/pretty/offload/offload_kernel.rs b/tests/pretty/offload/offload_kernel.rs new file mode 100644 index 0000000000000..1084242a35f8e --- /dev/null +++ b/tests/pretty/offload/offload_kernel.rs @@ -0,0 +1,20 @@ +//@ only-nightly +//@ revisions: host device + +//@ pretty-mode:expanded +//@ pretty-compare-only +//@[host] pp-exact:offload_kernel.host.pp +//@[device] pp-exact:offload_kernel.device.pp + +//@[device] compile-flags: -Zunstable-options -Zoffload=Device + +#![feature(gpu_offload)] + +use std::offload::offload_kernel; + +#[offload_kernel] +fn foo(a: &[f32], b: &[f32], c: *mut f32) { + *c = a[0] + b[0]; +} + +fn main() {} diff --git a/tests/rustdoc-html/intra-doc/self-impl-in-submodule-84827.rs b/tests/rustdoc-html/intra-doc/self-impl-in-submodule-84827.rs new file mode 100644 index 0000000000000..fba5a787cb720 --- /dev/null +++ b/tests/rustdoc-html/intra-doc/self-impl-in-submodule-84827.rs @@ -0,0 +1,43 @@ +// https://github.com/rust-lang/rust/issues/84827 +// +// Regression test for resolving `Self` in intra-doc links inside an `impl` +// block in a submodule. The `Self` type comes from the impl, not from names +// in scope, so: +// 1. It resolves even when the implemented type is not in scope. +// 2. It resolves to the actual `Self` type, not to a different type with +// the same name that happens to be in scope. + +#![crate_name = "foo"] +#![deny(rustdoc::broken_intra_doc_links)] +#![allow(unused_imports)] + +pub struct Foo { + pub foo: i32, +} + +// Case 1: `Foo` is not in scope inside `bar`, but `Self::foo` still resolves +// to the field on `crate::Foo`. +pub mod bar { + //@ has foo/struct.Foo.html '//a[@href="struct.Foo.html#structfield.foo"]' 'Self::foo' + impl crate::Foo { + /// Baz the [`Self::foo`]. + pub fn baz(&self) {} + } +} + +// Case 2: A different type named `Foo` is in scope inside `baz`. `Self::foo` +// must still resolve to `crate::Foo::foo`, not to `crate::other::Foo` (which +// is a unit struct and has no `foo` field). +pub mod baz { + use crate::other::Foo; + + //@ has foo/struct.Foo.html '//a[@href="struct.Foo.html#structfield.foo"]' 'Self::foo' + impl crate::Foo { + /// Quux the [`Self::foo`]. + pub fn quux(&self) {} + } +} + +pub mod other { + pub struct Foo; +} diff --git a/tests/ui/derives/debug/derives-span-Debug.stderr b/tests/ui/derives/debug/derives-span-Debug.stderr index e4a2560db4512..0f322e37b05c3 100644 --- a/tests/ui/derives/debug/derives-span-Debug.stderr +++ b/tests/ui/derives/debug/derives-span-Debug.stderr @@ -7,7 +7,6 @@ LL | #[derive(Debug)] LL | x: Error, | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | LL + #[derive(Debug)] @@ -23,7 +22,6 @@ LL | #[derive(Debug)] LL | Error, | ^^^^^ the trait `Debug` is not implemented for `Error` | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | LL + #[derive(Debug)] @@ -39,7 +37,6 @@ LL | struct Struct { LL | x: Error, | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | LL + #[derive(Debug)] @@ -55,7 +52,6 @@ LL | struct TupleStruct( LL | Error, | ^^^^^ the trait `Debug` is not implemented for `Error` | - = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/derives/redundant-derive-note-on-unimplemented.rs b/tests/ui/derives/redundant-derive-note-on-unimplemented.rs new file mode 100644 index 0000000000000..f708d3a48359c --- /dev/null +++ b/tests/ui/derives/redundant-derive-note-on-unimplemented.rs @@ -0,0 +1,15 @@ +// Regression test for the redundant `note: add `#[derive(Debug)]` to `X` or manually +// `impl Debug for X`` that was emitted alongside the `consider annotating X with +// `#[derive(Debug)]`` suggestion. When the derive suggestion is shown, the note is +// redundant and should be suppressed. +// +// See https://github.com/rust-lang/rust/issues/157118 + +#[derive(Debug)] +struct S(T); + +struct X; + +fn main() { + println!("{:?}", S(X)); //~ ERROR `X` doesn't implement `Debug` +} diff --git a/tests/ui/derives/redundant-derive-note-on-unimplemented.stderr b/tests/ui/derives/redundant-derive-note-on-unimplemented.stderr new file mode 100644 index 0000000000000..dcb1639593a58 --- /dev/null +++ b/tests/ui/derives/redundant-derive-note-on-unimplemented.stderr @@ -0,0 +1,31 @@ +error[E0277]: `X` doesn't implement `Debug` + --> $DIR/redundant-derive-note-on-unimplemented.rs:14:22 + | +LL | println!("{:?}", S(X)); + | ---- ^^^^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter + | + = help: the trait `Debug` is not implemented for `X` +help: the trait `Debug` is implemented for `S` + --> $DIR/redundant-derive-note-on-unimplemented.rs:8:10 + | +LL | #[derive(Debug)] + | ^^^^^ +note: required for `S` to implement `Debug` + --> $DIR/redundant-derive-note-on-unimplemented.rs:9:8 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +LL | struct S(T); + | ^ - type parameter would need to implement `Debug` + = help: consider manually implementing `Debug` to avoid undesired bounds +help: consider annotating `X` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct X; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/fmt/format-args-argument-span.stderr b/tests/ui/fmt/format-args-argument-span.stderr index a486abe821b74..76fc178bb3d44 100644 --- a/tests/ui/fmt/format-args-argument-span.stderr +++ b/tests/ui/fmt/format-args-argument-span.stderr @@ -25,7 +25,6 @@ LL | println!("{x} {x:?} {x}"); | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `DisplayOnly` - = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` help: consider annotating `DisplayOnly` with `#[derive(Debug)]` | LL + #[derive(Debug)] @@ -41,7 +40,6 @@ LL | println!("{x} {x:?} {x}", x = DisplayOnly); | required by this formatting parameter | = help: the trait `Debug` is not implemented for `DisplayOnly` - = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` help: consider annotating `DisplayOnly` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/fmt/non-source-literals.stderr b/tests/ui/fmt/non-source-literals.stderr index 953a4a64fd8dc..39dc35653618f 100644 --- a/tests/ui/fmt/non-source-literals.stderr +++ b/tests/ui/fmt/non-source-literals.stderr @@ -31,7 +31,6 @@ LL | let _ = format!(concat!("{:", "?}"), NonDebug); | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `NonDebug` - = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` help: consider annotating `NonDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] @@ -45,7 +44,6 @@ LL | let _ = format!(concat!("{", "0", ":?}"), NonDebug); | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `NonDebug` - = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` help: consider annotating `NonDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr index 23bc9dc0f844e..ce63a69b927c5 100644 --- a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -4,7 +4,6 @@ error[E0277]: `Foo` doesn't implement `Debug` LL | a.unwrap(); | ^^^^^^ the trait `Debug` is not implemented for `Foo` | - = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` note: required by a bound in `Result::::unwrap` --> $SRC_DIR/core/src/result.rs:LL:COL help: consider annotating `Foo` with `#[derive(Debug)]` diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 40dda93ad015c..d41fcced9be4a 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -4,7 +4,6 @@ error[E0277]: `Dummy` doesn't implement `Debug` 105 | dbg!(lib::Dummy); | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy` | - = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/on-unimplemented/no-debug.stderr b/tests/ui/on-unimplemented/no-debug.stderr index 3c3b8d2e20541..c078e0fd42531 100644 --- a/tests/ui/on-unimplemented/no-debug.stderr +++ b/tests/ui/on-unimplemented/no-debug.stderr @@ -7,7 +7,6 @@ LL | println!("{:?} {:?}", Foo, Bar); | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Foo` - = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` help: consider annotating `Foo` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 4cdeb184bd915..f8699f9e55e24 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -4,7 +4,6 @@ error[E0277]: `NotDebug` doesn't implement `Debug` LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug` | - = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index d2f780bdbcb43..96c45d285e8d0 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -18,7 +18,6 @@ error[E0277]: `MyError` doesn't implement `Debug` 4 | impl std::error::Error for MyError {} | ^^^^^^^ the trait `Debug` is not implemented for `MyError` | - = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError` note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL help: consider annotating `MyError` with `#[derive(Debug)]` diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index b28f39ced542d..0d05bd9d91bbf 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -6,7 +6,6 @@ LL | #[derive(Debug)] LL | struct Outer(Inner); | ^^^^^^^^ the trait `Debug` is not implemented for `a::Inner` | - = note: add `#[derive(Debug)]` to `a::Inner` or manually `impl Debug for a::Inner` help: consider annotating `a::Inner` with `#[derive(Debug)]` | LL + #[derive(Debug)]