Skip to content
Draft
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
351 changes: 154 additions & 197 deletions Cargo.lock

Large diffs are not rendered by default.

40 changes: 38 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use rustc_errors::{Applicability, msg};
use rustc_feature::AttributeStability;
use rustc_hir::Target;
use rustc_hir::attrs::{
AttributeKind, CfgEntry, CfgHideShow, DocAttribute, DocCfgHideShow, DocCfgHideShowValue,
DocInline, HideOrShow,
AttributeKind, CfgEntry, CfgHideShow, DocAttribute, DocAttributeSyntax, DocCfgHideShow,
DocCfgHideShowValue, DocInline, HideOrShow,
};
use rustc_session::errors::feature_err;
use rustc_span::{Span, Symbol, edition, sym};
Expand Down Expand Up @@ -666,6 +666,42 @@ impl DocParser {
}
}
}
Some(sym::syntax) => {
if !cx.features().rustdoc_texmath() {
feature_err(
cx.sess(),
sym::rustdoc_texmath,
path.span(),
msg!("the `#[doc(syntax)]` attribute is unstable"),
)
.emit();
}
let span = args.span().unwrap_or(path.span());
let tex_math_dollars = if let Some(v) = args.as_name_value()
&& let Some(syntax) = v.value_as_str()
{
match syntax.as_str() {
"+tex_math_dollars" => true,
"-tex_math_dollars" => false,
_ => {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
MalformedDoc,
span,
);
false
}
}
} else {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
MalformedDoc,
span,
);
false
};
self.attribute.syntax = Some(DocAttributeSyntax { tex_math_dollars, span });
}
Some(sym::spotlight) => {
let span = path.span();
cx.emit_lint(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ declare_features! (
(internal, rustdoc_internals, "1.58.0", Some(90418)),
/// Allows using the `rustdoc::missing_doc_code_examples` lint
(unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)),
/// Allows using the `#[doc(math_syntax)]` and `#[doc(no_math_syntax)]` crate attributes
(unstable, rustdoc_texmath, "CURRENT_RUSTC_VERSION", Some(34261)),
/// Introduces a hierarchy of `Sized` traits (RFC 3729).
(unstable, sized_hierarchy, "1.89.0", Some(144404)),
/// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
Expand Down
30 changes: 30 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,34 @@ pub struct DocAttribute {
// #[doc(test(...))]
pub test_attrs: ThinVec<Span>,
pub no_crate_inject: Option<Span>,

// #[doc(syntax="-tex_math_dollars")] // disable
// #[doc(syntax="+tex_math_dollars")] // enable
pub syntax: Option<DocAttributeSyntax>,
}

#[derive(Clone, Debug, Eq, PartialEq, StableHash, Decodable, Encodable)]
pub struct DocAttributeSyntax {
pub tex_math_dollars: bool,
pub span: Span,
}

impl PrintAttribute for DocAttributeSyntax {
fn should_render(&self) -> bool {
true
}
fn print_attribute(&self, p: &mut rustc_ast_pretty::pp::Printer) {
match self {
DocAttributeSyntax { tex_math_dollars, span: _ } => {
p.word("syntax");
p.word("=");
p.word(format!(
r#""{}tex_math_dollars""#,
if *tex_math_dollars { "+" } else { "-" }
));
}
}
}
}

impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute {
Expand Down Expand Up @@ -648,6 +676,7 @@ impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute
rust_logo,
test_attrs,
no_crate_inject,
syntax,
} = self;
rustc_serialize::Encodable::<E>::encode(first_span, encoder);
rustc_serialize::Encodable::<E>::encode(aliases, encoder);
Expand Down Expand Up @@ -678,6 +707,7 @@ impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute
rustc_serialize::Encodable::<E>::encode(rust_logo, encoder);
rustc_serialize::Encodable::<E>::encode(test_attrs, encoder);
rustc_serialize::Encodable::<E>::encode(no_crate_inject, encoder);
rustc_serialize::Encodable::<E>::encode(syntax, encoder);
}
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use rustc_data_structures::svh::Svh;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{ErrorGuaranteed, catch_fatal_errors};
use rustc_hir as hir;
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
use rustc_hir::attrs::{DocAttributeSyntax, EiiDecl, EiiImpl, StrippedCfgItem};
use rustc_hir::def::{DefKind, DocLinkResMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdSet, LocalModDefId};
use rustc_hir::lang_items::{LangItem, LanguageItems};
Expand Down Expand Up @@ -1491,6 +1491,11 @@ rustc_queries! {
desc { "checking whether `{}` is `doc(notable_trait)`", tcx.def_path_str(def_id) }
}

/// Return the math syntax configuration for this crates' doc attribute, or `Unspecified` if there is none.
query doc_attribute_syntax(def_id: DefId) -> Option<&'tcx DocAttributeSyntax> {
desc { "looking up math syntax for crate {}", tcx.def_path_str(def_id) }
}

/// Returns the attributes on the item at `def_id`.
///
/// Do not use this directly, use `tcx.get_attrs` instead.
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_data_structures::stable_hash::{StableHash, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorGuaranteed;
use rustc_hashes::Hash128;
use rustc_hir::attrs::DocAttributeSyntax;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::limit::Limit;
Expand Down Expand Up @@ -1672,6 +1673,45 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
find_attr!(tcx, def_id, Doc(doc) if doc.notable_trait.is_some())
}

/// Get doc attribute math syntax declaration, if any.
pub fn doc_attribute_syntax(tcx: TyCtxt<'_>, mut def_id: DefId) -> Option<&'_ DocAttributeSyntax> {
loop {
use rustc_hir::def::DefKind;
if matches!(
tcx.def_kind(def_id),
// the set of defs that can have `#[doc(syntax)]` attached to them
|DefKind::Mod| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::AssocTy
| DefKind::Fn
| DefKind::Const { .. }
| DefKind::Static { nested: false, .. }
| DefKind::AssocFn
| DefKind::AssocConst { .. }
| DefKind::Macro(_)
| DefKind::Use
| DefKind::Field
| DefKind::Impl { .. }
| DefKind::Closure
) {
let attr = find_attr!(
tcx,
def_id,
Doc(doc) if doc.syntax.is_some() => doc.syntax.as_ref().unwrap()
);
if attr.is_some() {
return attr;
}
}
def_id = tcx.opt_parent(def_id)?;
}
}

/// Determines whether an item is an intrinsic (which may be via Abi or via the `rustc_intrinsic` attribute).
///
/// We double check the feature gate here because whether a function may be defined as an intrinsic causes
Expand Down Expand Up @@ -1700,6 +1740,7 @@ pub fn provide(providers: &mut Providers) {
reveal_opaque_types_in_bounds,
is_doc_hidden,
is_doc_notable_trait,
doc_attribute_syntax,
intrinsic_raw,
..*providers
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// already checked in attr_parsing
no_crate_inject: _,
attribute,
syntax: _,
} = attr;

for (alias, span) in aliases {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
indexmap = "2.4.0"
itertools = "0.12"
pulldown-cmark = { version = "0.11", features = [
pulldown-cmark = { version = "0.13", features = [
"html",
], default-features = false }
rustc_arena = { path = "../rustc_arena" }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5505,7 +5505,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}

let mut need_traits_in_scope = false;
for path_str in rustdoc::attrs_to_preprocessed_links(attrs) {
for path_str in rustdoc::attrs_to_preprocessed_links(self.r.tcx, attrs) {
// Resolve all namespaces due to no disambiguator or for diagnostics.
let mut any_resolved = false;
let mut need_assoc = false;
Expand Down
30 changes: 23 additions & 7 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_ast::token::DocFragmentKind;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
use rustc_hir::attrs::DocAttributeSyntax;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
use rustc_span::source_map::SourceMap;
Expand Down Expand Up @@ -248,12 +249,17 @@ pub fn prepare_to_doc_link_resolution(
}

/// Options for rendering Markdown in the main body of documentation.
pub fn main_body_opts() -> Options {
pub fn main_body_opts(doc_syntax: Option<&DocAttributeSyntax>) -> Options {
Options::ENABLE_TABLES
| Options::ENABLE_FOOTNOTES
| Options::ENABLE_STRIKETHROUGH
| Options::ENABLE_TASKLISTS
| Options::ENABLE_SMART_PUNCTUATION
| (if let Some(DocAttributeSyntax { tex_math_dollars: true, .. }) = doc_syntax {
Options::ENABLE_MATH
} else {
Options::empty()
})
}

fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<Symbol, MalformedGenerics> {
Expand Down Expand Up @@ -404,20 +410,30 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool {
| LinkType::Shortcut
| LinkType::ShortcutUnknown => true,
LinkType::Autolink | LinkType::Email => false,
LinkType::WikiLink { has_pothole: _ } => unreachable!("wikilinks aren't used in rustdoc"),
}
}

/// 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(attrs: &[ast::Attribute]) -> Vec<Box<str>> {
pub(crate) fn attrs_to_preprocessed_links(
tcx: TyCtxt<'_>,
attrs: &[ast::Attribute],
) -> Vec<Box<str>> {
let (doc_fragments, other_attrs) =
attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false);
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next();
let mut links = doc.as_deref().map(parse_links).unwrap_or_default();
let mut links = prepare_to_doc_link_resolution(&doc_fragments)
.into_iter()
.next()
.map(|(def_id, doc)| {
let doc_syntax = def_id.and_then(|def_id| tcx.doc_attribute_syntax(def_id));
parse_links(&doc, doc_syntax)
})
.unwrap_or_default();

for attr in other_attrs {
if let Some(note) = attr.deprecation_note() {
links.extend(parse_links(note.as_str()));
links.extend(parse_links(note.as_str(), None));
}
}

Expand All @@ -426,11 +442,11 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s

/// Similar version of `markdown_links` from rustdoc.
/// This will collect destination links and display text if exists.
fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
fn parse_links<'md>(doc: &'md str, doc_syntax: Option<&DocAttributeSyntax>) -> Vec<Box<str>> {
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
let mut event_iter = Parser::new_with_broken_link_callback(
doc,
main_body_opts(),
main_body_opts(doc_syntax),
Some(&mut broken_link_callback),
);
let mut links = Vec::new();
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,7 @@ symbols! {
rustdoc,
rustdoc_internals,
rustdoc_missing_doc_code_examples,
rustdoc_texmath,
rustfmt,
rvalue_static_promotion,
rvector,
Expand Down Expand Up @@ -2063,6 +2064,7 @@ symbols! {
sve_tuple_set,
sym,
sync,
syntax,
synthetic,
t32,
target,
Expand Down
Loading
Loading