Skip to content
Closed
34 changes: 34 additions & 0 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,34 @@ impl AttributeExt for Attribute {
}
}

fn deprecation_note(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
let meta = &normal.item;

// #[deprecated = "..."]
if let Some(s) = meta.value_str() {
return Some(s);
}

// #[deprecated(note = "...")]
if let Some(list) = meta.meta_item_list() {
for nested in list {
if let Some(mi) = nested.meta_item()
&& mi.path == sym::note
&& let Some(s) = mi.value_str()
{
return Some(s);
}
}
}

None
}
_ => None,
}
}

fn doc_resolution_scope(&self) -> Option<AttrStyle> {
match &self.kind {
AttrKind::DocComment(..) => Some(self.style),
Expand Down Expand Up @@ -277,6 +305,7 @@ impl Attribute {

pub fn may_have_doc_links(&self) -> bool {
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
}

/// Extracts the MetaItem from inside this Attribute.
Expand Down Expand Up @@ -873,6 +902,11 @@ pub trait AttributeExt: Debug {
/// * `#[doc(...)]` returns `None`.
fn doc_str(&self) -> Option<Symbol>;

/// Returns the deprecation note if this is deprecation attribute.
/// * `#[deprecated = "note"]` returns `Some("note")`.
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
fn deprecation_note(&self) -> Option<Symbol>;

fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup?
codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err}
.note = it will be distributed via rustup in the future

codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err}

codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_codegen_llvm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_unavailable)]
pub(crate) struct AutoDiffComponentUnavailable;
pub(crate) struct AutoDiffComponentUnavailable {
pub err: String,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_missing)]
#[note]
pub(crate) struct AutoDiffComponentMissing {
pub err: String,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_without_lto)]
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
return Ok(());
}

sym::amdgpu_dispatch_ptr => {
let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]);
// Relying on `LLVMBuildPointerCast` to produce an addrspacecast
self.pointercast(val, self.type_ptr())
}

_ if name.as_str().starts_with("simd_") => {
// Unpack non-power-of-2 #[repr(packed, simd)] arguments.
// This gives them the expected layout of a regular #[repr(simd)] vector.
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,14 @@ impl CodegenBackend for LlvmCodegenBackend {

use crate::back::lto::enable_autodiff_settings;
if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable);
match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
Ok(_) => {}
Err(llvm::EnzymeLibraryError::NotFound { err }) => {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err });
}
Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err });
}
}
enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
}
Expand Down
34 changes: 25 additions & 9 deletions compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub(crate) mod Enzyme_AD {
fn load_ptr_by_symbol_mut_void(
lib: &libloading::Library,
bytes: &[u8],
) -> Result<*mut c_void, Box<dyn std::error::Error>> {
) -> Result<*mut c_void, libloading::Error> {
unsafe {
let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
// libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
Expand Down Expand Up @@ -192,15 +192,27 @@ pub(crate) mod Enzyme_AD {

static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();

#[derive(Debug)]
pub(crate) enum EnzymeLibraryError {
NotFound { err: String },
LoadFailed { err: String },
}

impl From<libloading::Error> for EnzymeLibraryError {
fn from(err: libloading::Error) -> Self {
Self::LoadFailed { err: format!("{err:?}") }
}
}

impl EnzymeWrapper {
/// Initialize EnzymeWrapper with the given sysroot if not already initialized.
/// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
pub(crate) fn get_or_init(
sysroot: &rustc_session::config::Sysroot,
) -> Result<MutexGuard<'static, Self>, Box<dyn std::error::Error>> {
) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
let w = Self::call_dynamic(sysroot)?;
Ok::<_, Box<dyn std::error::Error>>(Mutex::new(w))
Ok::<_, EnzymeLibraryError>(Mutex::new(w))
})?;

Ok(mtx.lock().unwrap())
Expand Down Expand Up @@ -351,7 +363,7 @@ pub(crate) mod Enzyme_AD {
#[allow(non_snake_case)]
fn call_dynamic(
sysroot: &rustc_session::config::Sysroot,
) -> Result<Self, Box<dyn std::error::Error>> {
) -> Result<Self, EnzymeLibraryError> {
let enzyme_path = Self::get_enzyme_path(sysroot)?;
let lib = unsafe { libloading::Library::new(enzyme_path)? };

Expand Down Expand Up @@ -416,7 +428,7 @@ pub(crate) mod Enzyme_AD {
})
}

fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, String> {
fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, EnzymeLibraryError> {
let llvm_version_major = unsafe { LLVMRustVersionMajor() };

let path_buf = sysroot
Expand All @@ -434,15 +446,19 @@ pub(crate) mod Enzyme_AD {
.map(|p| p.join("lib").display().to_string())
.collect::<Vec<String>>()
.join("\n* ");
format!(
"failed to find a `libEnzyme-{llvm_version_major}` folder \
EnzymeLibraryError::NotFound {
err: format!(
"failed to find a `libEnzyme-{llvm_version_major}` folder \
in the sysroot candidates:\n* {candidates}"
)
),
}
})?;

Ok(path_buf
.to_str()
.ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))?
.ok_or_else(|| EnzymeLibraryError::LoadFailed {
err: format!("invalid UTF-8 in path: {}", path_buf.display()),
})?
.to_string())
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
| sym::unreachable
| sym::cold_path
| sym::breakpoint
| sym::amdgpu_dispatch_ptr
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid
| sym::assert_inhabited
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,14 @@ impl AttributeExt for Attribute {
}
}

#[inline]
fn deprecation_note(&self) -> Option<Symbol> {
match &self {
Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note,
_ => None,
}
}

fn is_automatically_derived_attr(&self) -> bool {
matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)))
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::add_with_overflow
| sym::aggregate_raw_ptr
| sym::align_of
| sym::amdgpu_dispatch_ptr
| sym::assert_inhabited
| sym::assert_mem_uninitialized_valid
| sym::assert_zero_valid
Expand Down Expand Up @@ -285,6 +286,7 @@ pub(crate) fn check_intrinsic_type(
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
sym::autodiff => (4, 0, vec![param(0), param(1), param(2)], param(3)),
sym::abort => (0, 0, vec![], tcx.types.never),
sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),
sym::unreachable => (0, 0, vec![], tcx.types.never),
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,17 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool {
/// Simplified version of `preprocessed_markdown_links` from rustdoc.
/// Must return at least the same links as it, but may add some more links on top of that.
pub(crate) fn attrs_to_preprocessed_links<A: AttributeExt + Clone>(attrs: &[A]) -> Vec<Box<str>> {
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
let (doc_fragments, other_attrs) =
attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false);
let mut doc =
prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap_or_default();

for attr in other_attrs {
if let Some(note) = attr.deprecation_note() {
doc += note.as_str();
doc += "\n";
}
}

parse_links(&doc)
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ symbols! {
alu32,
always,
amdgpu,
amdgpu_dispatch_ptr,
analysis,
and,
and_then,
Expand Down
23 changes: 23 additions & 0 deletions library/core/src/intrinsics/gpu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! Intrinsics for GPU targets.
//!
//! Intrinsics in this module are intended for use on GPU targets.
//! They can be target specific but in general GPU targets are similar.

#![unstable(feature = "gpu_intrinsics", issue = "none")]

/// Returns a pointer to the HSA kernel dispatch packet.
///
/// A `gpu-kernel` on amdgpu is always launched through a kernel dispatch packet.
/// The dispatch packet contains the workgroup size, launch size and other data.
/// The content is defined by the [HSA Platform System Architecture Specification],
/// which is implemented e.g. in AMD's [hsa.h].
/// The intrinsic returns a unit pointer so that rustc does not need to know the packet struct.
/// The pointer is valid for the whole lifetime of the program.
///
/// [HSA Platform System Architecture Specification]: https://hsafoundation.com/wp-content/uploads/2021/02/HSA-SysArch-1.2.pdf
/// [hsa.h]: https://github.com/ROCm/rocm-systems/blob/rocm-7.1.0/projects/rocr-runtime/runtime/hsa-runtime/inc/hsa.h#L2959
#[rustc_nounwind]
#[rustc_intrinsic]
#[cfg(target_arch = "amdgpu")]
#[must_use = "returns a pointer that does nothing unless used"]
pub fn amdgpu_dispatch_ptr() -> *const ();
1 change: 1 addition & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ use crate::{mem, ptr};

mod bounds;
pub mod fallback;
pub mod gpu;
pub mod mir;
pub mod simd;

Expand Down
18 changes: 18 additions & 0 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,24 @@ impl<T> AtomicPtr<T> {
unsafe { &*ptr.cast() }
}

/// Creates a new `AtomicPtr` initialized with a null pointer.
///
/// # Examples
///
/// ```
/// #![feature(atomic_ptr_null)]
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let atomic_ptr = AtomicPtr::<()>::null();
/// assert!(atomic_ptr.load(Ordering::Relaxed).is_null());
/// ```
#[inline]
#[must_use]
#[unstable(feature = "atomic_ptr_null", issue = "150733")]
pub const fn null() -> AtomicPtr<T> {
AtomicPtr::new(crate::ptr::null_mut())
}

/// Returns a mutable reference to the underlying pointer.
///
/// This is safe because the mutable reference guarantees that no other threads are
Expand Down
10 changes: 10 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{fmt, iter};
use arrayvec::ArrayVec;
use itertools::Either;
use rustc_abi::{ExternAbi, VariantIdx};
use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation, DocAttribute};
Expand Down Expand Up @@ -450,7 +451,16 @@ impl Item {
}

pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
let deprecation_notes = self
.attrs
.other_attrs
.iter()
.filter_map(|attr| attr.deprecation_note().map(|_| attr.span()));

span_of_fragments(&self.attrs.doc_strings)
.into_iter()
.chain(deprecation_notes)
.reduce(|a, b| a.to(b))
.unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
}

Expand Down
26 changes: 22 additions & 4 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,11 @@ pub(crate) struct MarkdownWithToc<'a> {
}
/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
/// and includes no paragraph tags.
pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap);
pub(crate) struct MarkdownItemInfo<'a> {
pub(crate) content: &'a str,
pub(crate) links: &'a [RenderedLink],
pub(crate) ids: &'a mut IdMap,
}
/// A tuple struct like `Markdown` that renders only the first paragraph.
pub(crate) struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]);

Expand Down Expand Up @@ -1459,15 +1463,28 @@ impl MarkdownWithToc<'_> {
}
}

impl MarkdownItemInfo<'_> {
impl<'a> MarkdownItemInfo<'a> {
pub(crate) fn new(content: &'a str, links: &'a [RenderedLink], ids: &'a mut IdMap) -> Self {
Self { content, links, ids }
}

pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
let MarkdownItemInfo(md, ids) = self;
let MarkdownItemInfo { content: md, links, ids } = self;

// This is actually common enough to special-case
if md.is_empty() {
return Ok(());
}
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();

let replacer = move |broken_link: BrokenLink<'_>| {
links
.iter()
.find(|link| *link.original_text == *broken_link.reference)
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
};

let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(replacer));
let p = p.into_offset_iter();

// Treat inline HTML as plain text.
let p = p.map(|event| match event.0 {
Expand All @@ -1477,6 +1494,7 @@ impl MarkdownItemInfo<'_> {

ids.handle_footnotes(|ids, existing_footnotes| {
let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
let p = SpannedLinkReplacer::new(p, links);
let p = footnotes::Footnotes::new(p, existing_footnotes);
let p = TableWrapper::new(p.map(|(ev, _)| ev));
let p = p.filter(|event| {
Expand Down
Loading
Loading