Auto merge of #145970 - GuillaumeGomez:rollup-pr11qds, r=GuillaumeGomez
Rollup of 6 pull requests Successful merges: - rust-lang/rust#142472 (Add new `doc(attribute = "...")` attribute) - rust-lang/rust#145368 (CFI: Make `lto` and `linker-plugin-lto` work the same for `compiler_builtins`) - rust-lang/rust#145853 (Improve error messages around invalid literals in attribute arguments) - rust-lang/rust#145920 (bootstrap: Explicitly mark the end of a failed test's captured output) - rust-lang/rust#145937 (add doc-hidden to exports in attribute prelude) - rust-lang/rust#145965 (Move exporting of profiler and sanitizer symbols to the LLVM backend) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f2824da98d
53 changed files with 514 additions and 194 deletions
|
|
@ -188,6 +188,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
notable_trait => doc_notable_trait
|
||||
}
|
||||
"meant for internal use only" {
|
||||
attribute => rustdoc_internals
|
||||
keyword => rustdoc_internals
|
||||
fake_variadic => rustdoc_internals
|
||||
search_unbox => rustdoc_internals
|
||||
|
|
|
|||
|
|
@ -1,20 +1,30 @@
|
|||
// parsing
|
||||
// templates
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_feature::{AttributeTemplate, template};
|
||||
// data structures
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_hir::attrs::AttributeKind;
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_hir::lints::AttributeLintKind;
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_hir::{MethodKind, Target};
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
||||
#[doc(hidden)]
|
||||
pub(super) use thin_vec::ThinVec;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::attributes::{
|
||||
AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
|
||||
NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
|
||||
};
|
||||
// contexts
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::parser::*;
|
||||
// target checking
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::target_checking::Policy::{Allow, Error, Warn};
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind};
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_errors::{Diag, PResult};
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -379,22 +379,23 @@ struct MetaItemListParserContext<'a, 'sess> {
|
|||
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
|
||||
let uninterpolated_span = self.parser.token_uninterpolated_span();
|
||||
let Some(token_lit) = self.parser.eat_token_lit() else {
|
||||
return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char);
|
||||
};
|
||||
let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
|
||||
self.unsuffixed_meta_item_from_lit(token_lit)
|
||||
}
|
||||
|
||||
fn unsuffixed_meta_item_from_lit(
|
||||
&mut self,
|
||||
token_lit: token::Lit,
|
||||
) -> PResult<'sess, MetaItemLit> {
|
||||
let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
|
||||
Ok(lit) => lit,
|
||||
Err(err) => {
|
||||
let guar =
|
||||
report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
// the error literal's symbol so they can be pretty-printed faithfully.
|
||||
let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
|
||||
let symbol = Symbol::intern(&suffixless_lit.to_string());
|
||||
let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
|
||||
MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
|
||||
return Err(create_lit_error(
|
||||
&self.parser.psess,
|
||||
err,
|
||||
token_lit,
|
||||
self.parser.prev_token_uninterpolated_span(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -448,16 +449,28 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
}
|
||||
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> {
|
||||
match self.parse_unsuffixed_meta_item_lit() {
|
||||
Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
}
|
||||
|
||||
match self.parse_attr_item() {
|
||||
Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
if let Some(token_lit) = self.parser.eat_token_lit() {
|
||||
// If a literal token is parsed, we commit to parsing a MetaItemLit for better errors
|
||||
Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
|
||||
} else {
|
||||
let prev_pros = self.parser.approx_token_stream_pos();
|
||||
match self.parse_attr_item() {
|
||||
Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
|
||||
Err(err) => {
|
||||
// If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
|
||||
// If it didn't make progress we use the `expected_lit` from below
|
||||
if self.parser.approx_token_stream_pos() != prev_pros {
|
||||
Err(err)
|
||||
} else {
|
||||
err.cancel();
|
||||
Err(self.expected_lit())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_lit(&mut self) -> Diag<'sess> {
|
||||
let mut err = InvalidMetaItem {
|
||||
span: self.parser.token.span,
|
||||
descr: token_descr(&self.parser.token),
|
||||
|
|
@ -492,7 +505,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
self.parser.bump();
|
||||
}
|
||||
|
||||
Err(self.parser.dcx().create_err(err))
|
||||
self.parser.dcx().create_err(err)
|
||||
}
|
||||
|
||||
fn parse(
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file};
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::attrs::SanitizerSet;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_session::config::{self, Lto};
|
||||
|
|
@ -42,6 +43,37 @@ fn prepare_lto(
|
|||
.map(|symbol| CString::new(symbol.to_owned()).unwrap())
|
||||
.collect::<Vec<CString>>();
|
||||
|
||||
if cgcx.regular_module_config.instrument_coverage
|
||||
|| cgcx.regular_module_config.pgo_gen.enabled()
|
||||
{
|
||||
// These are weak symbols that point to the profile version and the
|
||||
// profile name, which need to be treated as exported so LTO doesn't nix
|
||||
// them.
|
||||
const PROFILER_WEAK_SYMBOLS: [&CStr; 2] =
|
||||
[c"__llvm_profile_raw_version", c"__llvm_profile_filename"];
|
||||
|
||||
symbols_below_threshold.extend(PROFILER_WEAK_SYMBOLS.iter().map(|&sym| sym.to_owned()));
|
||||
}
|
||||
|
||||
if cgcx.regular_module_config.sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
let mut msan_weak_symbols = Vec::new();
|
||||
|
||||
// Similar to profiling, preserve weak msan symbol during LTO.
|
||||
if cgcx.regular_module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) {
|
||||
msan_weak_symbols.push(c"__msan_keep_going");
|
||||
}
|
||||
|
||||
if cgcx.regular_module_config.sanitizer_memory_track_origins != 0 {
|
||||
msan_weak_symbols.push(c"__msan_track_origins");
|
||||
}
|
||||
|
||||
symbols_below_threshold.extend(msan_weak_symbols.into_iter().map(|sym| sym.to_owned()));
|
||||
}
|
||||
|
||||
// Preserve LLVM-injected, ASAN-related symbols.
|
||||
// See also https://github.com/rust-lang/rust/issues/113404.
|
||||
symbols_below_threshold.push(c"___asan_globals_registered".to_owned());
|
||||
|
||||
// __llvm_profile_counter_bias is pulled in at link time by an undefined reference to
|
||||
// __llvm_profile_runtime, therefore we won't know until link time if this symbol
|
||||
// should have default visibility.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam
|
|||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{SanitizerSet, TlsModel};
|
||||
use rustc_target::spec::TlsModel;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base::allocator_kind_for_codegen;
|
||||
|
|
@ -242,53 +242,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
|
||||
// These are weak symbols that point to the profile version and the
|
||||
// profile name, which need to be treated as exported so LTO doesn't nix
|
||||
// them.
|
||||
const PROFILER_WEAK_SYMBOLS: [&str; 2] =
|
||||
["__llvm_profile_raw_version", "__llvm_profile_filename"];
|
||||
|
||||
symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
|
||||
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
|
||||
(
|
||||
exported_symbol,
|
||||
SymbolExportInfo {
|
||||
level: SymbolExportLevel::C,
|
||||
kind: SymbolExportKind::Data,
|
||||
used: false,
|
||||
rustc_std_internal_symbol: false,
|
||||
},
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
let mut msan_weak_symbols = Vec::new();
|
||||
|
||||
// Similar to profiling, preserve weak msan symbol during LTO.
|
||||
if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
|
||||
msan_weak_symbols.push("__msan_keep_going");
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 {
|
||||
msan_weak_symbols.push("__msan_track_origins");
|
||||
}
|
||||
|
||||
symbols.extend(msan_weak_symbols.into_iter().map(|sym| {
|
||||
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
|
||||
(
|
||||
exported_symbol,
|
||||
SymbolExportInfo {
|
||||
level: SymbolExportLevel::C,
|
||||
kind: SymbolExportKind::Data,
|
||||
used: false,
|
||||
rustc_std_internal_symbol: false,
|
||||
},
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
// Sort so we get a stable incr. comp. hash.
|
||||
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
|
||||
|
||||
|
|
|
|||
|
|
@ -138,23 +138,12 @@ impl ModuleConfig {
|
|||
|
||||
let emit_obj = if !should_emit_obj {
|
||||
EmitObj::None
|
||||
} else if sess.target.obj_is_bitcode
|
||||
|| (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
|
||||
{
|
||||
} else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() {
|
||||
// This case is selected if the target uses objects as bitcode, or
|
||||
// if linker plugin LTO is enabled. In the linker plugin LTO case
|
||||
// the assumption is that the final link-step will read the bitcode
|
||||
// and convert it to object code. This may be done by either the
|
||||
// native linker or rustc itself.
|
||||
//
|
||||
// Note, however, that the linker-plugin-lto requested here is
|
||||
// explicitly ignored for `#![no_builtins]` crates. These crates are
|
||||
// specifically ignored by rustc's LTO passes and wouldn't work if
|
||||
// loaded into the linker. These crates define symbols that LLVM
|
||||
// lowers intrinsics to, and these symbol dependencies aren't known
|
||||
// until after codegen. As a result any crate marked
|
||||
// `#![no_builtins]` is assumed to not participate in LTO and
|
||||
// instead goes on to generate object code.
|
||||
EmitObj::Bitcode
|
||||
} else if need_bitcode_in_object(tcx) {
|
||||
EmitObj::ObjectCode(BitcodeSection::Full)
|
||||
|
|
|
|||
|
|
@ -1226,12 +1226,6 @@ extern "C" void LLVMRustPrintPasses() {
|
|||
extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
|
||||
size_t Len) {
|
||||
auto PreserveFunctions = [=](const GlobalValue &GV) {
|
||||
// Preserve LLVM-injected, ASAN-related symbols.
|
||||
// See also https://github.com/rust-lang/rust/issues/113404.
|
||||
if (GV.getName() == "___asan_globals_registered") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preserve symbols exported from Rust modules.
|
||||
for (size_t I = 0; I < Len; I++) {
|
||||
if (GV.getName() == Symbols[I]) {
|
||||
|
|
|
|||
|
|
@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> {
|
|||
(token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
|
||||
}
|
||||
|
||||
pub fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
|
||||
fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
|
||||
ast::MetaItemLit {
|
||||
symbol: name,
|
||||
suffix: None,
|
||||
|
|
@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_missing_lit<L>(
|
||||
fn handle_missing_lit<L>(
|
||||
&mut self,
|
||||
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
|
||||
) -> PResult<'a, L> {
|
||||
|
|
|
|||
|
|
@ -145,6 +145,10 @@ passes_doc_alias_start_end =
|
|||
passes_doc_attr_not_crate_level =
|
||||
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
|
||||
|
||||
passes_doc_attribute_not_attribute =
|
||||
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
|
||||
.help = only existing builtin attributes are allowed in core/std
|
||||
|
||||
passes_doc_cfg_hide_takes_list =
|
||||
`#[doc(cfg_hide(...))]` takes a list of attributes
|
||||
|
||||
|
|
@ -173,16 +177,16 @@ passes_doc_inline_only_use =
|
|||
passes_doc_invalid =
|
||||
invalid `doc` attribute
|
||||
|
||||
passes_doc_keyword_empty_mod =
|
||||
`#[doc(keyword = "...")]` should be used on empty modules
|
||||
passes_doc_keyword_attribute_empty_mod =
|
||||
`#[doc({$attr_name} = "...")]` should be used on empty modules
|
||||
|
||||
passes_doc_keyword_attribute_not_mod =
|
||||
`#[doc({$attr_name} = "...")]` should be used on modules
|
||||
|
||||
passes_doc_keyword_not_keyword =
|
||||
nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]`
|
||||
.help = only existing keywords are allowed in core/std
|
||||
|
||||
passes_doc_keyword_not_mod =
|
||||
`#[doc(keyword = "...")]` should be used on modules
|
||||
|
||||
passes_doc_keyword_only_impl =
|
||||
`#[doc(keyword = "...")]` should be used on impl blocks
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,21 @@ impl IntoDiagArg for ProcMacroKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum DocFakeItemKind {
|
||||
Attribute,
|
||||
Keyword,
|
||||
}
|
||||
|
||||
impl DocFakeItemKind {
|
||||
fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::Attribute => "attribute",
|
||||
Self::Keyword => "keyword",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CheckAttrVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
|
|
@ -853,7 +868,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) {
|
||||
fn check_doc_keyword_and_attribute(
|
||||
&self,
|
||||
meta: &MetaItemInner,
|
||||
hir_id: HirId,
|
||||
attr_kind: DocFakeItemKind,
|
||||
) {
|
||||
fn is_doc_keyword(s: Symbol) -> bool {
|
||||
// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we
|
||||
// can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the
|
||||
|
|
@ -861,9 +881,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy
|
||||
}
|
||||
|
||||
let doc_keyword = match meta.value_str() {
|
||||
// FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`.
|
||||
fn is_builtin_attr(s: Symbol) -> bool {
|
||||
rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains_key(&s)
|
||||
}
|
||||
|
||||
let value = match meta.value_str() {
|
||||
Some(value) if value != sym::empty => value,
|
||||
_ => return self.doc_attr_str_error(meta, "keyword"),
|
||||
_ => return self.doc_attr_str_error(meta, attr_kind.name()),
|
||||
};
|
||||
|
||||
let item_kind = match self.tcx.hir_node(hir_id) {
|
||||
|
|
@ -873,20 +898,38 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
match item_kind {
|
||||
Some(ItemKind::Mod(_, module)) => {
|
||||
if !module.item_ids.is_empty() {
|
||||
self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
|
||||
self.dcx().emit_err(errors::DocKeywordAttributeEmptyMod {
|
||||
span: meta.span(),
|
||||
attr_name: attr_kind.name(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() });
|
||||
self.dcx().emit_err(errors::DocKeywordAttributeNotMod {
|
||||
span: meta.span(),
|
||||
attr_name: attr_kind.name(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !is_doc_keyword(doc_keyword) {
|
||||
self.dcx().emit_err(errors::DocKeywordNotKeyword {
|
||||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
keyword: doc_keyword,
|
||||
});
|
||||
match attr_kind {
|
||||
DocFakeItemKind::Keyword => {
|
||||
if !is_doc_keyword(value) {
|
||||
self.dcx().emit_err(errors::DocKeywordNotKeyword {
|
||||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
keyword: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
DocFakeItemKind::Attribute => {
|
||||
if !is_builtin_attr(value) {
|
||||
self.dcx().emit_err(errors::DocAttributeNotAttribute {
|
||||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
attribute: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1146,7 +1189,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
|
||||
Some(sym::keyword) => {
|
||||
if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
|
||||
self.check_doc_keyword(meta, hir_id);
|
||||
self.check_doc_keyword_and_attribute(
|
||||
meta,
|
||||
hir_id,
|
||||
DocFakeItemKind::Keyword,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Some(sym::attribute) => {
|
||||
if self.check_attr_not_crate_level(meta, hir_id, "attribute") {
|
||||
self.check_doc_keyword_and_attribute(
|
||||
meta,
|
||||
hir_id,
|
||||
DocFakeItemKind::Attribute,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -195,10 +195,11 @@ pub(crate) struct DocAliasMalformed {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_keyword_empty_mod)]
|
||||
pub(crate) struct DocKeywordEmptyMod {
|
||||
#[diag(passes_doc_keyword_attribute_empty_mod)]
|
||||
pub(crate) struct DocKeywordAttributeEmptyMod {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -211,10 +212,20 @@ pub(crate) struct DocKeywordNotKeyword {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_keyword_not_mod)]
|
||||
pub(crate) struct DocKeywordNotMod {
|
||||
#[diag(passes_doc_attribute_not_attribute)]
|
||||
#[help]
|
||||
pub(crate) struct DocAttributeNotAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attribute: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_doc_keyword_attribute_not_mod)]
|
||||
pub(crate) struct DocKeywordAttributeNotMod {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -5016,7 +5016,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
ResolveDocLinks::Exported
|
||||
if !maybe_exported.eval(self.r)
|
||||
&& !rustdoc::has_primitive_or_keyword_docs(attrs) =>
|
||||
&& !rustdoc::has_primitive_or_keyword_or_attribute_docs(attrs) =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,8 +373,8 @@ pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
|
||||
pub fn has_primitive_or_keyword_docs(attrs: &[impl AttributeExt]) -> bool {
|
||||
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`.
|
||||
pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::rustc_doc_primitive) {
|
||||
return true;
|
||||
|
|
@ -382,7 +382,7 @@ pub fn has_primitive_or_keyword_docs(attrs: &[impl AttributeExt]) -> bool {
|
|||
&& let Some(items) = attr.meta_item_list()
|
||||
{
|
||||
for item in items {
|
||||
if item.has_name(sym::keyword) {
|
||||
if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,6 +384,10 @@ pub fn report_lit_error(
|
|||
lit: token::Lit,
|
||||
span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
create_lit_error(psess, err, lit, span).emit()
|
||||
}
|
||||
|
||||
pub fn create_lit_error(psess: &ParseSess, err: LitError, lit: token::Lit, span: Span) -> Diag<'_> {
|
||||
// Checks if `s` looks like i32 or u1234 etc.
|
||||
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
|
||||
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
|
||||
|
|
@ -414,32 +418,32 @@ pub fn report_lit_error(
|
|||
let dcx = psess.dcx();
|
||||
match err {
|
||||
LitError::InvalidSuffix(suffix) => {
|
||||
dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix })
|
||||
dcx.create_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix })
|
||||
}
|
||||
LitError::InvalidIntSuffix(suffix) => {
|
||||
let suf = suffix.as_str();
|
||||
if looks_like_width_suffix(&['i', 'u'], suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() })
|
||||
dcx.create_err(InvalidIntLiteralWidth { span, width: suf[1..].into() })
|
||||
} else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) {
|
||||
dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed })
|
||||
dcx.create_err(InvalidNumLiteralBasePrefix { span, fixed })
|
||||
} else {
|
||||
dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() })
|
||||
dcx.create_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() })
|
||||
}
|
||||
}
|
||||
LitError::InvalidFloatSuffix(suffix) => {
|
||||
let suf = suffix.as_str();
|
||||
if looks_like_width_suffix(&['f'], suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() })
|
||||
dcx.create_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() })
|
||||
} else {
|
||||
dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() })
|
||||
dcx.create_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() })
|
||||
}
|
||||
}
|
||||
LitError::NonDecimalFloat(base) => match base {
|
||||
16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }),
|
||||
8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }),
|
||||
2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }),
|
||||
16 => dcx.create_err(HexadecimalFloatLiteralNotSupported { span }),
|
||||
8 => dcx.create_err(OctalFloatLiteralNotSupported { span }),
|
||||
2 => dcx.create_err(BinaryFloatLiteralNotSupported { span }),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
LitError::IntTooLarge(base) => {
|
||||
|
|
@ -450,7 +454,7 @@ pub fn report_lit_error(
|
|||
16 => format!("{max:#x}"),
|
||||
_ => format!("{max}"),
|
||||
};
|
||||
dcx.emit_err(IntLiteralTooLarge { span, limit })
|
||||
dcx.create_err(IntLiteralTooLarge { span, limit })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,6 +541,7 @@ symbols! {
|
|||
att_syntax,
|
||||
attr,
|
||||
attr_literals,
|
||||
attribute,
|
||||
attributes,
|
||||
audit_that,
|
||||
augmented_assignments,
|
||||
|
|
|
|||
|
|
@ -250,8 +250,14 @@ impl<'a> Renderer<'a> {
|
|||
if failure.stdout.is_some() || failure.message.is_some() {
|
||||
println!("---- {} stdout ----", failure.name);
|
||||
if let Some(stdout) = &failure.stdout {
|
||||
println!("{stdout}");
|
||||
// Captured test output normally ends with a newline,
|
||||
// so only use `println!` if it doesn't.
|
||||
print!("{stdout}");
|
||||
if !stdout.ends_with('\n') {
|
||||
println!("\n\\ (no newline at end of output)");
|
||||
}
|
||||
}
|
||||
println!("---- {} stdout end ----", failure.name);
|
||||
if let Some(message) = &failure.message {
|
||||
println!("NOTE: {message}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ to enable.
|
|||
|
||||
### Document keywords
|
||||
|
||||
This is for Rust compiler internal use only.
|
||||
This is for internal use in the std library.
|
||||
|
||||
Rust keywords are documented in the standard library (look for `match` for example).
|
||||
|
||||
|
|
@ -211,6 +211,23 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
|
|||
mod empty_mod {}
|
||||
```
|
||||
|
||||
### Document builtin attributes
|
||||
|
||||
This is for internal use in the std library.
|
||||
|
||||
Rust builtin attributes are documented in the standard library (look for `repr` for example).
|
||||
|
||||
To do so, the `#[doc(attribute = "...")]` attribute is used. Example:
|
||||
|
||||
```rust
|
||||
#![feature(rustdoc_internals)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
/// Some documentation about the attribute.
|
||||
#[doc(attribute = "repr")]
|
||||
mod empty_mod {}
|
||||
```
|
||||
|
||||
### Use the Rust logo as the crate logo
|
||||
|
||||
This is for official Rust project use only.
|
||||
|
|
|
|||
|
|
@ -226,15 +226,28 @@ impl ExternalCrate {
|
|||
}
|
||||
|
||||
pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
|
||||
fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> {
|
||||
self.retrieve_keywords_or_documented_attributes(tcx, sym::keyword)
|
||||
}
|
||||
pub(crate) fn documented_attributes(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> impl Iterator<Item = (DefId, Symbol)> {
|
||||
self.retrieve_keywords_or_documented_attributes(tcx, sym::attribute)
|
||||
}
|
||||
|
||||
fn retrieve_keywords_or_documented_attributes(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
name: Symbol,
|
||||
) -> impl Iterator<Item = (DefId, Symbol)> {
|
||||
let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> {
|
||||
tcx.get_attrs(did, sym::doc)
|
||||
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
|
||||
.filter(|meta| meta.has_name(sym::keyword))
|
||||
.filter(|meta| meta.has_name(name))
|
||||
.find_map(|meta| meta.value_str())
|
||||
.map(|value| (did, value))
|
||||
}
|
||||
|
||||
self.mapped_root_modules(tcx, as_keyword)
|
||||
};
|
||||
self.mapped_root_modules(tcx, as_target)
|
||||
}
|
||||
|
||||
pub(crate) fn primitives(
|
||||
|
|
@ -592,6 +605,20 @@ impl Item {
|
|||
pub(crate) fn is_keyword(&self) -> bool {
|
||||
self.type_() == ItemType::Keyword
|
||||
}
|
||||
pub(crate) fn is_attribute(&self) -> bool {
|
||||
self.type_() == ItemType::Attribute
|
||||
}
|
||||
/// Returns `true` if the item kind is one of the following:
|
||||
///
|
||||
/// * `ItemType::Primitive`
|
||||
/// * `ItemType::Keyword`
|
||||
/// * `ItemType::Attribute`
|
||||
///
|
||||
/// They are considered fake because they only exist thanks to their
|
||||
/// `#[doc(primitive|keyword|attribute)]` attribute.
|
||||
pub(crate) fn is_fake_item(&self) -> bool {
|
||||
matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute)
|
||||
}
|
||||
pub(crate) fn is_stripped(&self) -> bool {
|
||||
match self.kind {
|
||||
StrippedItem(..) => true,
|
||||
|
|
@ -735,7 +762,9 @@ impl Item {
|
|||
// Primitives and Keywords are written in the source code as private modules.
|
||||
// The modules need to be private so that nobody actually uses them, but the
|
||||
// keywords and primitives that they are documenting are public.
|
||||
ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
|
||||
ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
|
||||
return Some(Visibility::Public);
|
||||
}
|
||||
// Variant fields inherit their enum's visibility.
|
||||
StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
|
||||
return None;
|
||||
|
|
@ -942,7 +971,12 @@ pub(crate) enum ItemKind {
|
|||
AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
|
||||
/// An item that has been stripped by a rustdoc pass
|
||||
StrippedItem(Box<ItemKind>),
|
||||
/// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
|
||||
/// to generate documentation for Rust keywords.
|
||||
KeywordItem,
|
||||
/// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
|
||||
/// to generate documentation for Rust builtin attributes.
|
||||
AttributeItem,
|
||||
}
|
||||
|
||||
impl ItemKind {
|
||||
|
|
@ -983,7 +1017,8 @@ impl ItemKind {
|
|||
| RequiredAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| StrippedItem(_)
|
||||
| KeywordItem => [].iter(),
|
||||
| KeywordItem
|
||||
| AttributeItem => [].iter(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
|||
let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
|
||||
let primitives = local_crate.primitives(cx.tcx);
|
||||
let keywords = local_crate.keywords(cx.tcx);
|
||||
let documented_attributes = local_crate.documented_attributes(cx.tcx);
|
||||
{
|
||||
let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() };
|
||||
m.items.extend(primitives.map(|(def_id, prim)| {
|
||||
|
|
@ -73,6 +74,9 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
|||
m.items.extend(keywords.map(|(def_id, kw)| {
|
||||
Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx)
|
||||
}));
|
||||
m.items.extend(documented_attributes.into_iter().map(|(def_id, kw)| {
|
||||
Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::AttributeItem, cx)
|
||||
}));
|
||||
}
|
||||
|
||||
Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) }
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ pub(crate) trait DocFolder: Sized {
|
|||
| ImplAssocConstItem(..)
|
||||
| RequiredAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| KeywordItem => kind,
|
||||
| KeywordItem
|
||||
| AttributeItem => kind,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -372,7 +372,8 @@ impl DocFolder for CacheBuilder<'_, '_> {
|
|||
| clean::RequiredAssocTypeItem(..)
|
||||
| clean::AssocTypeItem(..)
|
||||
| clean::StrippedItem(..)
|
||||
| clean::KeywordItem => {
|
||||
| clean::KeywordItem
|
||||
| clean::AttributeItem => {
|
||||
// FIXME: Do these need handling?
|
||||
// The person writing this comment doesn't know.
|
||||
// So would rather leave them to an expert,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ pub(crate) enum ItemType {
|
|||
TraitAlias = 25,
|
||||
// This number is reserved for use in JavaScript
|
||||
// Generic = 26,
|
||||
Attribute = 27,
|
||||
}
|
||||
|
||||
impl Serialize for ItemType {
|
||||
|
|
@ -148,6 +149,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
|
|||
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
|
||||
clean::ForeignTypeItem => ItemType::ForeignType,
|
||||
clean::KeywordItem => ItemType::Keyword,
|
||||
clean::AttributeItem => ItemType::Attribute,
|
||||
clean::TraitAliasItem(..) => ItemType::TraitAlias,
|
||||
clean::ProcMacroItem(mac) => match mac.kind {
|
||||
MacroKind::Bang => ItemType::Macro,
|
||||
|
|
@ -236,6 +238,7 @@ impl ItemType {
|
|||
ItemType::ProcAttribute => "attr",
|
||||
ItemType::ProcDerive => "derive",
|
||||
ItemType::TraitAlias => "traitalias",
|
||||
ItemType::Attribute => "attribute",
|
||||
}
|
||||
}
|
||||
pub(crate) fn is_method(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ impl<'tcx> Context<'tcx> {
|
|||
} else {
|
||||
it.name.as_ref().unwrap().as_str()
|
||||
};
|
||||
if !it.is_primitive() && !it.is_keyword() {
|
||||
if !it.is_fake_item() {
|
||||
if !is_module {
|
||||
title.push_str(" in ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2535,6 +2535,7 @@ pub(crate) enum ItemSection {
|
|||
AssociatedConstants,
|
||||
ForeignTypes,
|
||||
Keywords,
|
||||
Attributes,
|
||||
AttributeMacros,
|
||||
DeriveMacros,
|
||||
TraitAliases,
|
||||
|
|
@ -2567,6 +2568,7 @@ impl ItemSection {
|
|||
AssociatedConstants,
|
||||
ForeignTypes,
|
||||
Keywords,
|
||||
Attributes,
|
||||
AttributeMacros,
|
||||
DeriveMacros,
|
||||
TraitAliases,
|
||||
|
|
@ -2596,6 +2598,7 @@ impl ItemSection {
|
|||
Self::AssociatedConstants => "associated-consts",
|
||||
Self::ForeignTypes => "foreign-types",
|
||||
Self::Keywords => "keywords",
|
||||
Self::Attributes => "attributes",
|
||||
Self::AttributeMacros => "attributes",
|
||||
Self::DeriveMacros => "derives",
|
||||
Self::TraitAliases => "trait-aliases",
|
||||
|
|
@ -2625,6 +2628,7 @@ impl ItemSection {
|
|||
Self::AssociatedConstants => "Associated Constants",
|
||||
Self::ForeignTypes => "Foreign Types",
|
||||
Self::Keywords => "Keywords",
|
||||
Self::Attributes => "Attributes",
|
||||
Self::AttributeMacros => "Attribute Macros",
|
||||
Self::DeriveMacros => "Derive Macros",
|
||||
Self::TraitAliases => "Trait Aliases",
|
||||
|
|
@ -2655,6 +2659,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
|
|||
ItemType::AssocConst => ItemSection::AssociatedConstants,
|
||||
ItemType::ForeignType => ItemSection::ForeignTypes,
|
||||
ItemType::Keyword => ItemSection::Keywords,
|
||||
ItemType::Attribute => ItemSection::Attributes,
|
||||
ItemType::ProcAttribute => ItemSection::AttributeMacros,
|
||||
ItemType::ProcDerive => ItemSection::DeriveMacros,
|
||||
ItemType::TraitAlias => ItemSection::TraitAliases,
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp
|
|||
clean::ConstantItem(..) => "Constant ",
|
||||
clean::ForeignTypeItem => "Foreign Type ",
|
||||
clean::KeywordItem => "Keyword ",
|
||||
clean::AttributeItem => "Attribute ",
|
||||
clean::TraitAliasItem(..) => "Trait Alias ",
|
||||
_ => {
|
||||
// We don't generate pages for any other type.
|
||||
|
|
@ -193,7 +194,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp
|
|||
let src_href =
|
||||
if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None };
|
||||
|
||||
let path_components = if item.is_primitive() || item.is_keyword() {
|
||||
let path_components = if item.is_fake_item() {
|
||||
vec![]
|
||||
} else {
|
||||
let cur = &cx.current;
|
||||
|
|
@ -252,7 +253,9 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp
|
|||
clean::ForeignTypeItem => {
|
||||
write!(buf, "{}", item_foreign_type(cx, item))
|
||||
}
|
||||
clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)),
|
||||
clean::KeywordItem | clean::AttributeItem => {
|
||||
write!(buf, "{}", item_keyword_or_attribute(cx, item))
|
||||
}
|
||||
clean::TraitAliasItem(ta) => {
|
||||
write!(buf, "{}", item_trait_alias(cx, item, ta))
|
||||
}
|
||||
|
|
@ -2151,7 +2154,7 @@ fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
|
|||
})
|
||||
}
|
||||
|
||||
fn item_keyword(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
|
||||
fn item_keyword_or_attribute(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
|
||||
document(cx, it, None, HeadingOffset::H2)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ nav.sub {
|
|||
--function-link-color: #ad7c37;
|
||||
--macro-link-color: #068000;
|
||||
--keyword-link-color: #3873ad;
|
||||
--attribute-link-color: #3873ad;
|
||||
--mod-link-color: #3873ad;
|
||||
--link-color: #3873ad;
|
||||
--sidebar-link-color: #356da4;
|
||||
|
|
@ -180,6 +181,7 @@ nav.sub {
|
|||
--function-link-color: #2bab63;
|
||||
--macro-link-color: #09bd00;
|
||||
--keyword-link-color: #d2991d;
|
||||
--attribute-link-color: #d2991d;
|
||||
--mod-link-color: #d2991d;
|
||||
--link-color: #d2991d;
|
||||
--sidebar-link-color: #fdbf35;
|
||||
|
|
|
|||
|
|
@ -400,6 +400,10 @@ span.keyword, a.keyword {
|
|||
color: var(--keyword-link-color);
|
||||
}
|
||||
|
||||
span.attribute, a.attribute {
|
||||
color: var(--attribute-link-color);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-color);
|
||||
text-decoration: none;
|
||||
|
|
@ -3190,6 +3194,7 @@ by default.
|
|||
--function-link-color: #ad7c37;
|
||||
--macro-link-color: #068000;
|
||||
--keyword-link-color: #3873ad;
|
||||
--attribute-link-color: #3873ad;
|
||||
--mod-link-color: #3873ad;
|
||||
--link-color: #3873ad;
|
||||
--sidebar-link-color: #356da4;
|
||||
|
|
@ -3294,6 +3299,7 @@ by default.
|
|||
--function-link-color: #2bab63;
|
||||
--macro-link-color: #09bd00;
|
||||
--keyword-link-color: #d2991d;
|
||||
--attribute-link-color: #d2991d;
|
||||
--mod-link-color: #d2991d;
|
||||
--link-color: #d2991d;
|
||||
--sidebar-link-color: #fdbf35;
|
||||
|
|
@ -3407,6 +3413,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
|
|||
--function-link-color: #fdd687;
|
||||
--macro-link-color: #a37acc;
|
||||
--keyword-link-color: #39afd7;
|
||||
--attribute-link-color: #39afd7;
|
||||
--mod-link-color: #39afd7;
|
||||
--link-color: #39afd7;
|
||||
--sidebar-link-color: #53b1db;
|
||||
|
|
|
|||
|
|
@ -790,6 +790,7 @@ function preLoadCss(cssUrl) {
|
|||
//block("associatedconstant", "associated-consts", "Associated Constants");
|
||||
block("foreigntype", "foreign-types", "Foreign Types");
|
||||
block("keyword", "keywords", "Keywords");
|
||||
block("attribute", "attributes", "Attributes");
|
||||
block("attr", "attributes", "Attribute Macros");
|
||||
block("derive", "derives", "Derive Macros");
|
||||
block("traitalias", "trait-aliases", "Trait Aliases");
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ const itemTypes = [
|
|||
"derive",
|
||||
"traitalias", // 25
|
||||
"generic",
|
||||
"attribute",
|
||||
];
|
||||
|
||||
// used for special search precedence
|
||||
|
|
@ -2058,7 +2059,7 @@ class DocSearch {
|
|||
displayPath = item.modulePath + "::";
|
||||
href = this.rootPath + item.modulePath.replace(/::/g, "/") +
|
||||
"/index.html#reexport." + name;
|
||||
} else if (type === "primitive" || type === "keyword") {
|
||||
} else if (type === "primitive" || type === "keyword" || type === "attribute") {
|
||||
displayPath = "";
|
||||
exactPath = "";
|
||||
href = this.rootPath + path.replace(/::/g, "/") +
|
||||
|
|
@ -4560,6 +4561,8 @@ const longItemTypes = [
|
|||
"attribute macro",
|
||||
"derive macro",
|
||||
"trait alias",
|
||||
"",
|
||||
"attribute",
|
||||
];
|
||||
// @ts-expect-error
|
||||
let currentResults;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ impl JsonRenderer<'_> {
|
|||
let clean::ItemInner { name, item_id, .. } = *item.inner;
|
||||
let id = self.id_from_item(item);
|
||||
let inner = match item.kind {
|
||||
clean::KeywordItem => return None,
|
||||
clean::KeywordItem | clean::AttributeItem => return None,
|
||||
clean::StrippedItem(ref inner) => {
|
||||
match &**inner {
|
||||
// We document stripped modules as with `Module::is_stripped` set to
|
||||
|
|
@ -85,7 +85,7 @@ impl JsonRenderer<'_> {
|
|||
fn ids(&self, items: &[clean::Item]) -> Vec<Id> {
|
||||
items
|
||||
.iter()
|
||||
.filter(|i| !i.is_stripped() && !i.is_keyword())
|
||||
.filter(|i| !i.is_stripped() && !i.is_keyword() && !i.is_attribute())
|
||||
.map(|i| self.id_from_item(i))
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -93,7 +93,10 @@ impl JsonRenderer<'_> {
|
|||
fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec<Option<Id>> {
|
||||
items
|
||||
.iter()
|
||||
.map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(i)))
|
||||
.map(|i| {
|
||||
(!i.is_stripped() && !i.is_keyword() && !i.is_attribute())
|
||||
.then(|| self.id_from_item(i))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
@ -332,8 +335,8 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
|
|||
bounds: b.into_json(renderer),
|
||||
type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)),
|
||||
},
|
||||
// `convert_item` early returns `None` for stripped items and keywords.
|
||||
KeywordItem => unreachable!(),
|
||||
// `convert_item` early returns `None` for stripped items, keywords and attributes.
|
||||
KeywordItem | AttributeItem => unreachable!(),
|
||||
StrippedItem(inner) => {
|
||||
match inner.as_ref() {
|
||||
ModuleItem(m) => ItemEnum::Module(Module {
|
||||
|
|
@ -887,6 +890,7 @@ impl FromClean<ItemType> for ItemKind {
|
|||
AssocType => ItemKind::AssocType,
|
||||
ForeignType => ItemKind::ExternType,
|
||||
Keyword => ItemKind::Keyword,
|
||||
Attribute => ItemKind::Attribute,
|
||||
TraitAlias => ItemKind::TraitAlias,
|
||||
ProcAttribute => ItemKind::ProcAttribute,
|
||||
ProcDerive => ItemKind::ProcDerive,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
|
|||
| clean::ImportItem(_)
|
||||
| clean::PrimitiveItem(_)
|
||||
| clean::KeywordItem
|
||||
| clean::AttributeItem
|
||||
| clean::ModuleItem(_)
|
||||
| clean::TraitAliasItem(_)
|
||||
| clean::ForeignFunctionItem(..)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_hir::{Mutability, Safety};
|
|||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_resolve::rustdoc::{
|
||||
MalformedGenerics, has_primitive_or_keyword_docs, prepare_to_doc_link_resolution,
|
||||
MalformedGenerics, has_primitive_or_keyword_or_attribute_docs, prepare_to_doc_link_resolution,
|
||||
source_span_for_markdown_range, strip_generics_from_path,
|
||||
};
|
||||
use rustc_session::config::CrateType;
|
||||
|
|
@ -1073,7 +1073,7 @@ impl LinkCollector<'_, '_> {
|
|||
&& let Some(def_id) = item.item_id.as_def_id()
|
||||
&& let Some(def_id) = def_id.as_local()
|
||||
&& !self.cx.tcx.effective_visibilities(()).is_exported(def_id)
|
||||
&& !has_primitive_or_keyword_docs(&item.attrs.other_attrs)
|
||||
&& !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs)
|
||||
{
|
||||
// Skip link resolution for non-exported items.
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ impl DocFolder for StabilityPropagator<'_, '_> {
|
|||
| ItemKind::RequiredAssocTypeItem(..)
|
||||
| ItemKind::AssocTypeItem(..)
|
||||
| ItemKind::PrimitiveItem(..)
|
||||
| ItemKind::KeywordItem => own_stability,
|
||||
| ItemKind::KeywordItem
|
||||
| ItemKind::AttributeItem => own_stability,
|
||||
|
||||
ItemKind::StrippedItem(..) => unreachable!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ impl DocFolder for Stripper<'_, '_> {
|
|||
|
||||
// Keywords are never stripped
|
||||
clean::KeywordItem => {}
|
||||
// Attributes are never stripped
|
||||
clean::AttributeItem => {}
|
||||
}
|
||||
|
||||
let fastreturn = match i.kind {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ pub(crate) trait DocVisitor<'a>: Sized {
|
|||
| ImplAssocConstItem(..)
|
||||
| RequiredAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| KeywordItem => {}
|
||||
| KeywordItem
|
||||
| AttributeItem => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
|
|||
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
|
||||
// are deliberately not in a doc comment, because they need not be in public docs.)
|
||||
//
|
||||
// Latest feature: Add Attribute::MacroUse
|
||||
pub const FORMAT_VERSION: u32 = 55;
|
||||
// Latest feature: Add `ItemKind::Attribute`.
|
||||
pub const FORMAT_VERSION: u32 = 56;
|
||||
|
||||
/// The root of the emitted JSON blob.
|
||||
///
|
||||
|
|
@ -552,6 +552,11 @@ pub enum ItemKind {
|
|||
/// [`Item`]s of this kind only come from the come library and exist solely
|
||||
/// to carry documentation for the respective keywords.
|
||||
Keyword,
|
||||
/// An attribute declaration.
|
||||
///
|
||||
/// [`Item`]s of this kind only come from the core library and exist solely
|
||||
/// to carry documentation for the respective builtin attributes.
|
||||
Attribute,
|
||||
}
|
||||
|
||||
/// Specific fields of an item.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ pub(crate) enum Kind {
|
|||
AssocType,
|
||||
Primitive,
|
||||
Keyword,
|
||||
Attribute,
|
||||
// Not in ItemKind
|
||||
ProcMacro,
|
||||
}
|
||||
|
|
@ -53,6 +54,7 @@ impl Kind {
|
|||
ExternType => true,
|
||||
|
||||
// FIXME(adotinthevoid): I'm not sure if these are correct
|
||||
Attribute => false,
|
||||
Keyword => false,
|
||||
ProcAttribute => false,
|
||||
ProcDerive => false,
|
||||
|
|
@ -109,6 +111,7 @@ impl Kind {
|
|||
Kind::Primitive => false,
|
||||
Kind::Keyword => false,
|
||||
Kind::ProcMacro => false,
|
||||
Kind::Attribute => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +166,7 @@ impl Kind {
|
|||
match s.kind {
|
||||
ItemKind::AssocConst => AssocConst,
|
||||
ItemKind::AssocType => AssocType,
|
||||
ItemKind::Attribute => Attribute,
|
||||
ItemKind::Constant => Constant,
|
||||
ItemKind::Enum => Enum,
|
||||
ItemKind::ExternCrate => ExternCrate,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ show-text: true
|
|||
define-function: (
|
||||
"check-colors",
|
||||
[theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
|
||||
sidebar, sidebar_current, sidebar_current_background],
|
||||
attribute, sidebar, sidebar_current, sidebar_current_background],
|
||||
block {
|
||||
call-function: ("switch-theme", {"theme": |theme|})
|
||||
// Checking results colors.
|
||||
|
|
@ -22,6 +22,7 @@ define-function: (
|
|||
assert-css: (".item-table .type", {"color": |type|}, ALL)
|
||||
assert-css: (".item-table .union", {"color": |union|}, ALL)
|
||||
assert-css: (".item-table .keyword", {"color": |keyword|}, ALL)
|
||||
assert-css: (".item-table .attribute", {"color": |attribute|}, ALL)
|
||||
// Checking sidebar elements.
|
||||
assert-css: (
|
||||
".sidebar-elems li:not(.current) a",
|
||||
|
|
@ -58,6 +59,7 @@ call-function: (
|
|||
"type": "#ffa0a5",
|
||||
"union": "#ffa0a5",
|
||||
"keyword": "#39afd7",
|
||||
"attribute": "#39afd7",
|
||||
"sidebar": "#53b1db",
|
||||
"sidebar_current": "#ffb44c",
|
||||
"sidebar_current_background": "transparent",
|
||||
|
|
@ -76,6 +78,7 @@ call-function: (
|
|||
"type": "#2dbfb8",
|
||||
"union": "#2dbfb8",
|
||||
"keyword": "#d2991d",
|
||||
"attribute": "#d2991d",
|
||||
"sidebar": "#fdbf35",
|
||||
"sidebar_current": "#fdbf35",
|
||||
"sidebar_current_background": "#444",
|
||||
|
|
@ -94,6 +97,7 @@ call-function: (
|
|||
"type": "#ad378a",
|
||||
"union": "#ad378a",
|
||||
"keyword": "#3873ad",
|
||||
"attribute": "#3873ad",
|
||||
"sidebar": "#356da4",
|
||||
"sidebar_current": "#356da4",
|
||||
"sidebar_current_background": "#fff",
|
||||
|
|
|
|||
|
|
@ -65,3 +65,12 @@ assert-css: (
|
|||
"#keywords + .item-table dd",
|
||||
{"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
|
||||
)
|
||||
// attributes
|
||||
assert-css: (
|
||||
"#attributes + .item-table dt a",
|
||||
{"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
|
||||
)
|
||||
assert-css: (
|
||||
"#attributes + .item-table dd",
|
||||
{"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ define-function: (
|
|||
[
|
||||
theme, count_color, desc_color, path_color, bottom_border_color, keyword_color,
|
||||
struct_color, associatedtype_color, tymethod_color, method_color, structfield_color,
|
||||
structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, grey
|
||||
structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background,
|
||||
attribute_color, grey
|
||||
],
|
||||
block {
|
||||
call-function: ("switch-theme", {"theme": |theme|})
|
||||
|
|
@ -46,6 +47,11 @@ define-function: (
|
|||
"color": |keyword_color|,
|
||||
"hover_color": |keyword_color|,
|
||||
})
|
||||
call-function: ("check-result-color", {
|
||||
"result_kind": "attribute",
|
||||
"color": |attribute_color|,
|
||||
"hover_color": |attribute_color|,
|
||||
})
|
||||
call-function: ("check-result-color", {
|
||||
"result_kind": "struct",
|
||||
"color": |struct_color|,
|
||||
|
|
@ -155,6 +161,7 @@ call-function: ("check-search-color", {
|
|||
"path_color": "#0096cf",
|
||||
"bottom_border_color": "#aaa3",
|
||||
"keyword_color": "#39afd7",
|
||||
"attribute_color": "#39afd7",
|
||||
"struct_color": "#ffa0a5",
|
||||
"associatedtype_color": "#39afd7",
|
||||
"tymethod_color": "#fdd687",
|
||||
|
|
@ -176,6 +183,7 @@ call-function: ("check-search-color", {
|
|||
"path_color": "#ddd",
|
||||
"bottom_border_color": "#aaa3",
|
||||
"keyword_color": "#d2991d",
|
||||
"attribute_color": "#d2991d",
|
||||
"struct_color": "#2dbfb8",
|
||||
"associatedtype_color": "#d2991d",
|
||||
"tymethod_color": "#2bab63",
|
||||
|
|
@ -197,6 +205,7 @@ call-function: ("check-search-color", {
|
|||
"path_color": "#000",
|
||||
"bottom_border_color": "#aaa3",
|
||||
"keyword_color": "#3873ad",
|
||||
"attribute_color": "#3873ad",
|
||||
"struct_color": "#ad378a",
|
||||
"associatedtype_color": "#3873ad",
|
||||
"tymethod_color": "#ad7c37",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ define-function: (
|
|||
enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover,
|
||||
trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
|
||||
type_hover_background, keyword, keyword_hover, keyword_hover_background,
|
||||
attribute, attribute_hover, attribute_hover_background,
|
||||
],
|
||||
block {
|
||||
call-function: ("switch-theme", {"theme": |theme|})
|
||||
|
|
@ -85,6 +86,16 @@ define-function: (
|
|||
".sidebar .block.keyword a:hover",
|
||||
{"color": |keyword_hover|, "background-color": |keyword_hover_background|},
|
||||
)
|
||||
// Attribute
|
||||
assert-css: (
|
||||
".sidebar .block.attribute a",
|
||||
{"color": |attribute|, "background-color": "rgba(0, 0, 0, 0)"},
|
||||
)
|
||||
move-cursor-to: ".sidebar .block.attribute a"
|
||||
assert-css: (
|
||||
".sidebar .block.attribute a:hover",
|
||||
{"color": |attribute_hover|, "background-color": |attribute_hover_background|},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -113,6 +124,9 @@ call-function: (
|
|||
"keyword": "#53b1db",
|
||||
"keyword_hover": "#ffb44c",
|
||||
"keyword_hover_background": "transparent",
|
||||
"attribute": "#53b1db",
|
||||
"attribute_hover": "#ffb44c",
|
||||
"attribute_hover_background": "transparent",
|
||||
}
|
||||
)
|
||||
call-function: (
|
||||
|
|
@ -140,6 +154,9 @@ call-function: (
|
|||
"keyword": "#fdbf35",
|
||||
"keyword_hover": "#fdbf35",
|
||||
"keyword_hover_background": "#444",
|
||||
"attribute": "#fdbf35",
|
||||
"attribute_hover": "#fdbf35",
|
||||
"attribute_hover_background": "#444",
|
||||
}
|
||||
)
|
||||
call-function: (
|
||||
|
|
@ -167,5 +184,8 @@ call-function: (
|
|||
"keyword": "#356da4",
|
||||
"keyword_hover": "#356da4",
|
||||
"keyword_hover_background": "#fff",
|
||||
"attribute": "#356da4",
|
||||
"attribute_hover": "#356da4",
|
||||
"attribute_hover_background": "#fff",
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@ pub enum AnEnum {
|
|||
/// Some keyword.
|
||||
pub mod keyword {}
|
||||
|
||||
#[doc(attribute = "forbid")]
|
||||
/// Some attribute.
|
||||
pub mod repr {}
|
||||
|
||||
/// Just some type alias.
|
||||
pub type SomeType = u32;
|
||||
|
||||
|
|
|
|||
18
tests/rustdoc-json/doc_attribute.rs
Normal file
18
tests/rustdoc-json/doc_attribute.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Doc attributes (`#[doc(attribute = "...")]` should not be generated in rustdoc JSON output
|
||||
// and this test ensures it.
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
#![no_std]
|
||||
|
||||
//@ !has "$.index[?(@.name=='repr')]"
|
||||
//@ has "$.index[?(@.name=='foo')]"
|
||||
|
||||
#[doc(attribute = "repr")]
|
||||
/// this is a test!
|
||||
pub mod foo {}
|
||||
|
||||
//@ !has "$.index[?(@.name=='forbid')]"
|
||||
//@ !has "$.index[?(@.name=='bar')]"
|
||||
#[doc(attribute = "forbid")]
|
||||
/// hello
|
||||
mod bar {}
|
||||
7
tests/rustdoc-ui/doc-attribute-unsupported.rs
Normal file
7
tests/rustdoc-ui/doc-attribute-unsupported.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// This is currently not supported but should be!
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(attribute = "diagnostic::do_not_recommend")] //~ ERROR
|
||||
/// bla
|
||||
mod yup {}
|
||||
10
tests/rustdoc-ui/doc-attribute-unsupported.stderr
Normal file
10
tests/rustdoc-ui/doc-attribute-unsupported.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
error: nonexistent builtin attribute `diagnostic::do_not_recommend` used in `#[doc(attribute = "...")]`
|
||||
--> $DIR/doc-attribute-unsupported.rs:5:19
|
||||
|
|
||||
LL | #[doc(attribute = "diagnostic::do_not_recommend")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: only existing builtin attributes are allowed in core/std
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
10
tests/rustdoc-ui/invalid-attribute.rs
Normal file
10
tests/rustdoc-ui/invalid-attribute.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Testing the output when an invalid builtin attribute is passed as value
|
||||
// to `doc(attribute = "...")`.
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
#[doc(attribute = "foo df")] //~ ERROR
|
||||
mod foo {}
|
||||
|
||||
#[doc(attribute = "fooyi")] //~ ERROR
|
||||
mod foo2 {}
|
||||
18
tests/rustdoc-ui/invalid-attribute.stderr
Normal file
18
tests/rustdoc-ui/invalid-attribute.stderr
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
error: nonexistent builtin attribute `foo df` used in `#[doc(attribute = "...")]`
|
||||
--> $DIR/invalid-attribute.rs:6:19
|
||||
|
|
||||
LL | #[doc(attribute = "foo df")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: only existing builtin attributes are allowed in core/std
|
||||
|
||||
error: nonexistent builtin attribute `fooyi` used in `#[doc(attribute = "...")]`
|
||||
--> $DIR/invalid-attribute.rs:9:19
|
||||
|
|
||||
LL | #[doc(attribute = "fooyi")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: only existing builtin attributes are allowed in core/std
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
24
tests/rustdoc/doc-attribute.rs
Normal file
24
tests/rustdoc/doc-attribute.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Test checking the `#[doc(attribute = "...")]` attribute.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
//@ has foo/index.html '//h2[@id="attributes"]' 'Attributes'
|
||||
//@ has foo/index.html '//a[@href="attribute.no_mangle.html"]' 'no_mangle'
|
||||
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Attributes'
|
||||
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#attributes'
|
||||
//@ has foo/attribute.no_mangle.html '//h1' 'Attribute no_mangle'
|
||||
//@ has foo/attribute.no_mangle.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
|
||||
//@ has foo/index.html '//a/@href' '../foo/index.html'
|
||||
//@ !has foo/foo/index.html
|
||||
//@ !has-dir foo/foo
|
||||
//@ !has foo/index.html '//span' '🔒'
|
||||
#[doc(attribute = "no_mangle")]
|
||||
/// this is a test!
|
||||
mod foo{}
|
||||
|
||||
//@ has foo/attribute.repr.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
|
||||
#[doc(attribute = "repr")]
|
||||
/// hello
|
||||
mod bar {}
|
||||
|
|
@ -2,6 +2,10 @@
|
|||
/// wonderful
|
||||
mod foo {}
|
||||
|
||||
#[doc(attribute = "repr")] //~ ERROR: `#[doc(attribute)]` is meant for internal use only
|
||||
/// wonderful
|
||||
mod foo2 {}
|
||||
|
||||
trait Mine {}
|
||||
|
||||
#[doc(fake_variadic)] //~ ERROR: `#[doc(fake_variadic)]` is meant for internal use only
|
||||
|
|
|
|||
|
|
@ -8,8 +8,18 @@ LL | #[doc(keyword = "match")]
|
|||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `#[doc(attribute)]` is meant for internal use only
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:5:1
|
||||
|
|
||||
LL | #[doc(attribute = "repr")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
|
||||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `#[doc(fake_variadic)]` is meant for internal use only
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:7:1
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:11:1
|
||||
|
|
||||
LL | #[doc(fake_variadic)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -19,7 +29,7 @@ LL | #[doc(fake_variadic)]
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `#[doc(search_unbox)]` is meant for internal use only
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:10:1
|
||||
--> $DIR/feature-gate-rustdoc_internals.rs:14:1
|
||||
|
|
||||
LL | #[doc(search_unbox)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -28,6 +38,6 @@ LL | #[doc(search_unbox)]
|
|||
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -38,10 +38,14 @@ fn g() {}
|
|||
|
||||
#[link(name = "string"suffix)]
|
||||
//~^ ERROR suffixes on string literals are invalid
|
||||
//~| ERROR malformed `link` attribute input
|
||||
extern "C" {}
|
||||
|
||||
#[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
//~^ ERROR invalid suffix `suffix` for number literal
|
||||
//~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
#[rustc_confusables("blah"suffix)]
|
||||
//~^ ERROR suffixes on string literals are invalid
|
||||
fn woof() { }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,48 +160,20 @@ error: suffixes on string literals are invalid
|
|||
LL | #[link(name = "string"suffix)]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error[E0539]: malformed `link` attribute input
|
||||
--> $DIR/bad-lit-suffixes.rs:39:1
|
||||
|
|
||||
LL | #[link(name = "string"suffix)]
|
||||
| ^^^^^^^---------------------^^
|
||||
| |
|
||||
| expected this to be of the form `name = "..."`
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #[link(name = "string"suffix)]
|
||||
LL + #[link(name = "...")]
|
||||
|
|
||||
LL - #[link(name = "string"suffix)]
|
||||
LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]
|
||||
|
|
||||
LL - #[link(name = "string"suffix)]
|
||||
LL + #[link(name = "...", kind = "dylib|static|...")]
|
||||
|
|
||||
LL - #[link(name = "string"suffix)]
|
||||
LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]
|
||||
|
|
||||
= and 1 other candidate
|
||||
|
||||
error: invalid suffix `suffix` for number literal
|
||||
--> $DIR/bad-lit-suffixes.rs:44:41
|
||||
--> $DIR/bad-lit-suffixes.rs:43:41
|
||||
|
|
||||
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
| ^^^^^^^ invalid suffix `suffix`
|
||||
|
|
||||
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
|
||||
|
||||
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
|
||||
--> $DIR/bad-lit-suffixes.rs:44:1
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:48:25
|
||||
|
|
||||
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
|
||||
| | |
|
||||
| | expected an integer literal here
|
||||
| help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
|
||||
LL | #[rustc_confusables("blah"suffix)]
|
||||
| ^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: aborting due to 23 previous errors; 2 warnings emitted
|
||||
error: aborting due to 22 previous errors; 2 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
|
|
|||
22
tests/ui/sanitizer/cfi/no_builtins.rs
Normal file
22
tests/ui/sanitizer/cfi/no_builtins.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Verifies that `#![no_builtins]` crates can be built with linker-plugin-lto and CFI.
|
||||
// See Issue #142284
|
||||
//
|
||||
//@ needs-sanitizer-cfi
|
||||
//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
|
||||
//@ compile-flags: --crate-type rlib
|
||||
//@ build-pass
|
||||
|
||||
#![no_builtins]
|
||||
#![no_std]
|
||||
|
||||
pub static FUNC: fn() = initializer;
|
||||
|
||||
pub fn initializer() {
|
||||
call(fma_with_fma);
|
||||
}
|
||||
|
||||
pub fn call(fn_ptr: fn()) {
|
||||
fn_ptr();
|
||||
}
|
||||
|
||||
pub fn fma_with_fma() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue