Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
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
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
6 changes: 3 additions & 3 deletions src/doc/rustc/src/remap-source-paths.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`rustc` supports remapping source paths prefixes **as a best effort** in all compiler generated
output, including compiler diagnostics, debugging information, macro expansions, etc.

This is useful for normalizing build products, for example by removing the current directory
This is useful for normalizing build products, for example, by removing the current directory
out of the paths emitted into object files.

The remapping is done via the `--remap-path-prefix` option.
Expand Down Expand Up @@ -41,7 +41,7 @@ This example replaces all occurrences of `/home/user/project` in emitted paths w

## Caveats and Limitations

### Linkers generated paths
### Paths generated by linkers

On some platforms like `x86_64-pc-windows-msvc`, the linker may embed absolute host paths and compiler
arguments into debug info files (like `.pdb`) independently of `rustc`.
Expand All @@ -54,7 +54,7 @@ The `--remap-path-prefix` option does not affect these linker-generated paths.
### Textual replacement only

The remapping is strictly textual and does not account for different path separator conventions across
platforms. Care must be taken when specifying prefixes, especially on Windows where both `/` and `\` may
platforms. Care must be taken when specifying prefixes, especially on Windows, where both `/` and `\` may
appear in paths.

### External tools
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
2 changes: 1 addition & 1 deletion src/librustdoc/html/markdown/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ fn test_markdown_html_escape() {
fn t(input: &str, expect: &str) {
let mut idmap = IdMap::new();
let mut output = String::new();
MarkdownItemInfo(input, &mut idmap).write_into(&mut output).unwrap();
MarkdownItemInfo::new(input, &[], &mut idmap).write_into(&mut output).unwrap();
assert_eq!(output, expect, "original: {}", input);
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,8 @@ fn short_item_info(
if let Some(note) = note {
let note = note.as_str();
let mut id_map = cx.id_map.borrow_mut();
let html = MarkdownItemInfo(note, &mut id_map);
let links = item.links(cx);
let html = MarkdownItemInfo::new(note, &links, &mut id_map);
message.push_str(": ");
html.write_into(&mut message).unwrap();
}
Expand Down
Loading
Loading