diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b1071bf430851..335f3b7a9a011 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -235,12 +235,10 @@ impl Annotatable { pub fn derive_allowed(&self) -> bool { match *self { Annotatable::Stmt(ref stmt) => match stmt.kind { - ast::StmtKind::Item(ref item) => match item.kind { - ast::ItemKind::Struct(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Union(..) => true, - _ => false, - }, + ast::StmtKind::Item(ref item) => matches!( + item.kind, + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) + ), _ => false, }, Annotatable::Item(ref item) => match item.kind { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 37ff6b9b368e7..2da5bde028fc1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1134,7 +1134,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { // Collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later. - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } // AstFragmentKind::Expr requires the macro to emit an expression. return self @@ -1231,7 +1233,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cfg.configure_expr_kind(&mut expr.kind); if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } return self .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f01d44171056f..44dc6673564a5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2401,7 +2401,7 @@ impl StructField<'_> { // Still necessary in couple of places pub fn is_positional(&self) -> bool { let first = self.ident.as_str().as_bytes()[0]; - first >= b'0' && first <= b'9' + (b'0'..=b'9').contains(&first) } } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6539419aefb27..44fc4db7dc199 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -267,8 +267,8 @@ pub fn is_whitespace(c: char) -> bool { pub fn is_id_start(c: char) -> bool { // This is XID_Start OR '_' (which formally is not a XID_Start). // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) } @@ -279,9 +279,9 @@ pub fn is_id_start(c: char) -> bool { pub fn is_id_continue(c: char) -> bool { // This is exactly XID_Continue. // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) + || ('0'..='9').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c2d98b8e4ad37..af5972c6c81c7 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl { } } } + +declare_tool_lint! { + pub rustc::EXISTING_DOC_KEYWORD, + Allow, + "Check that documented keywords in std and core actually exist", + report_in_external_macro: true +} + +declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]); + +fn is_doc_keyword(s: Symbol) -> bool { + s <= kw::Union +} + +impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + for attr in item.attrs { + if !attr.has_name(sym::doc) { + continue; + } + if let Some(list) = attr.meta_item_list() { + for nested in list { + if nested.has_name(sym::keyword) { + let v = nested + .value_str() + .expect("#[doc(keyword = \"...\")] expected a value!"); + if is_doc_keyword(v) { + return; + } + cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { + lint.build(&format!( + "Found non-existing keyword `{}` used in \ + `#[doc(keyword = \"...\")]`", + v, + )) + .help("only existing keywords are allowed in core/std") + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81549be4b0915..80ef855c3859e 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -463,6 +463,8 @@ fn register_internals(store: &mut LintStore) { store.register_early_pass(|| box DefaultHashTypes::new()); store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| box LintPassImpl); + store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_late_pass(|| box ExistingDocKeyword); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| box TyTyKind); store.register_group( @@ -475,6 +477,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(EXISTING_DOC_KEYWORD), ], ); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f53a40278062c..c571ed7b61262 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1592,23 +1592,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } - fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { - let mut def_path_hashes = self.def_path_hash_cache.lock(); - let mut def_index_to_data = |index| { - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }; - if let Some(data) = &self.root.proc_macro_data { - std::iter::once(CRATE_DEF_INDEX) - .chain(data.macros.decode(self)) - .map(def_index_to_data) - .collect() - } else { - (0..self.num_def_ids()) - .map(|index| def_index_to_data(DefIndex::from_usize(index))) - .collect() - } - } - /// Get the `DepNodeIndex` corresponding this crate. The result of this /// method is cached in the `dep_node_index` field. fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2ffd239b2f06c..b7f2288521790 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -456,6 +456,10 @@ impl CStore { pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + + pub fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } } impl CrateStore for CStore { @@ -498,14 +502,6 @@ impl CrateStore for CStore { self.get_crate_data(def.krate).def_path_hash(def.index) } - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { - self.get_crate_data(cnum).all_def_path_hashes_and_def_ids() - } - - fn num_def_ids(&self, cnum: CrateNum) -> usize { - self.get_crate_data(cnum).num_def_ids() - } - // See `CrateMetadataRef::def_path_hash_to_def_id` for more details fn def_path_hash_to_def_id( &self, diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index bd7121ca1d70f..6d2c43874bc0f 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -189,8 +189,6 @@ pub trait CrateStore { fn def_kind(&self, def: DefId) -> DefKind; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; - fn num_def_ids(&self, cnum: CrateNum) -> usize; fn def_path_hash_to_def_id( &self, cnum: CrateNum, diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 275496647d948..187f6fab5181f 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -7,6 +7,7 @@ use std::collections::hash_map::Entry; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; +use std::fmt; use rustc_ast::Mutability; use rustc_hir::def_id::DefId; @@ -179,6 +180,28 @@ impl interpret::AllocMap for FxHashMap { crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum MemoryKind { + Heap, +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Heap => write!(f, "heap allocation"), + } + } +} + +impl interpret::MayLeak for MemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + match self { + MemoryKind::Heap => false, + } + } +} + impl interpret::MayLeak for ! { #[inline(always)] fn may_leak(self) -> bool { @@ -222,6 +245,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = MemoryKind; + type MemoryExtra = MemoryExtra; fn find_mir_or_eval_fn( @@ -317,7 +342,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let ptr = ecx.memory.allocate( Size::from_bytes(size as u64), align, - interpret::MemoryKind::ConstHeap, + interpret::MemoryKind::Machine(MemoryKind::Heap), ); ecx.write_scalar(Scalar::Ptr(ptr), dest)?; } diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index db996f72128a7..01d58c47e3ab9 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -25,19 +25,20 @@ use rustc_target::abi::Size; use rustc_ast::Mutability; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor}; +use crate::const_eval; -pub trait CompileTimeMachine<'mir, 'tcx> = Machine< +pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, - MemoryKind = !, + MemoryKind = T, PointerTag = (), ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxHashMap, Allocation)>, + MemoryMap = FxHashMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { +struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { /// The ectx from which we intern. ecx: &'rt mut InterpCx<'mir, 'tcx, M>, /// Previously encountered safe references. @@ -74,7 +75,7 @@ struct IsStaticOrFn; /// `immutable` things might become mutable if `ty` is not frozen. /// `ty` can be `None` if there is no potential interior mutability /// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( +fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, leftover_allocations: &'rt mut FxHashSet, alloc_id: AllocId, @@ -105,7 +106,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // changes in this function. match kind { MemoryKind::Stack - | MemoryKind::ConstHeap + | MemoryKind::Machine(const_eval::MemoryKind::Heap) | MemoryKind::Vtable | MemoryKind::CallerLocation => {} } @@ -141,7 +142,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( None } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + InternVisitor<'rt, 'mir, 'tcx, M> +{ fn intern_shallow( &mut self, alloc_id: AllocId, @@ -152,8 +155,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir } } -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for InternVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> { type V = MPlaceTy<'tcx>; @@ -290,7 +293,7 @@ pub enum InternKind { /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. #[tracing::instrument(skip(ecx))] -pub fn intern_const_alloc_recursive>( +pub fn intern_const_alloc_recursive>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, @@ -421,7 +424,9 @@ where Ok(()) } -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> + InterpCx<'mir, 'tcx, M> +{ /// A helper function that allocates memory for the layout given and gives you access to mutate /// it. Once your own mutation code is done, the backing `Allocation` is removed from the /// current `Memory` and returned. diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d4d..0bba027377229 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -366,9 +366,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type PointerTag = (); type ExtraFnVal = !; - type MemoryKind = !; - type MemoryMap = rustc_data_structures::fx::FxHashMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory + type MemoryMap = + rustc_data_structures::fx::FxHashMap, Allocation)>; + const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory type AllocExtra = (); type FrameExtra = (); @@ -407,7 +407,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _memory_extra: &Self::MemoryExtra, _id: AllocId, alloc: Cow<'b, Allocation>, - _kind: Option>, + _kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation (alloc, ()) diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 3294daabe6125..f3e373813ca53 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -27,9 +27,6 @@ use crate::util::pretty; pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, - /// Heap memory. - /// FIXME: this variant should be in const_eval - ConstHeap, /// Memory backing vtables. Error if ever deallocated. Vtable, /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. @@ -43,7 +40,6 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, - MemoryKind::ConstHeap => false, MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), @@ -55,7 +51,6 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::ConstHeap => write!(f, "heap allocation"), MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index abcf1862fd873..1d949e020ed5c 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -180,6 +180,8 @@ impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = !; + type MemoryExtra = (); fn find_mir_or_eval_fn( diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index 6c8965aa2e31f..bbbe568f17a8f 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -1859,7 +1859,7 @@ impl> Parser { } let n2 = self.decode_hex_escape()?; - if n2 < 0xDC00 || n2 > 0xDFFF { + if !(0xDC00..=0xDFFF).contains(&n2) { return self.error(LoneLeadingSurrogateInHexEscape); } let c = diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index b4beb3dc37689..5987fb2a19897 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -97,7 +97,7 @@ cfg_if::cfg_if! { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.offset(chunk_index as isize)); + let chunk = _mm_loadu_si128(ptr.add(chunk_index)); // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. @@ -253,7 +253,7 @@ fn analyze_source_file_generic( let pos = BytePos::from_usize(i) + output_offset; if char_len > 1 { - assert!(char_len >= 2 && char_len <= 4); + assert!((2..=4).contains(&char_len)); let mbc = MultiByteChar { pos, bytes: char_len as u8 }; multi_byte_chars.push(mbc); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 11a49d1ab887d..f63a73acbf4ba 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1015,10 +1015,7 @@ pub enum ExternalSourceKind { impl ExternalSource { pub fn is_absent(&self) -> bool { - match self { - ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false, - _ => true, - } + !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. }) } pub fn get_source(&self) -> Option<&Lrc> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f067cdb730864..e9b4eb6e4abe0 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -623,7 +623,7 @@ impl SourceMap { self.span_to_source(sp, |src, start_index, end_index| { src.get(start_index..end_index) .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + .ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } @@ -640,9 +640,7 @@ impl SourceMap { /// Returns the source snippet as `String` before the given `Span`. pub fn span_to_prev_source(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, _| { - src.get(..start_index) - .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 91b87fdc482de..e75ddb36ff876 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1363,15 +1363,13 @@ impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_raw { f.write_str("r#")?; - } else { - if self.symbol == kw::DollarCrate { - if let Some(span) = self.convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - if !converted.is_path_segment_keyword() { - f.write_str("::")?; - } - return fmt::Display::fmt(&converted, f); + } else if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; } + return fmt::Display::fmt(&converted, f); } } fmt::Display::fmt(&self.symbol, f) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b13019146568c..604835e6cc4a6 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1978,9 +1978,14 @@ fn const_str_ptr() { const B: &'static [u8; 2] = &A; const C: *const u8 = B as *const u8; - unsafe { + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + #[cfg(not(miri))] + { let foo = &A as *const u8; assert_eq!(foo, C); + } + + unsafe { assert_eq!(from_utf8_unchecked(&A), "hi"); assert_eq!(*C, A[0]); assert_eq!(*(&B[0] as *const u8), A[0]); diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4ed62a620c4df..0c65c1c9eb7e9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -403,7 +403,7 @@ impl<'a> Arguments<'a> { /// ```rust /// #![feature(fmt_as_str)] /// - /// use core::fmt::Arguments; + /// use std::fmt::Arguments; /// /// fn write_str(_: &str) { /* ... */ } /// diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index ab162638a1cfe..560dd25ecff42 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -21,7 +21,7 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let future = future::pending(); diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index af63e1bb097b8..9ae118e29f110 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -3,7 +3,7 @@ use crate::future::Future; use crate::pin::Pin; use crate::task::{Context, Poll}; -/// Creates a future that wraps a function returning `Poll`. +/// Creates a future that wraps a function returning [`Poll`]. /// /// Polling the future delegates to the wrapped function. /// @@ -13,7 +13,7 @@ use crate::task::{Context, Poll}; /// #![feature(future_poll_fn)] /// # async fn run() { /// use core::future::poll_fn; -/// use core::task::{Context, Poll}; +/// use std::task::{Context, Poll}; /// /// fn read_line(_cx: &mut Context<'_>) -> Poll { /// Poll::Ready("Hello, World!".into()) @@ -31,7 +31,7 @@ where PollFn { f } } -/// A Future that wraps a function returning `Poll`. +/// A Future that wraps a function returning [`Poll`]. /// /// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index e98f5c570bf3c..b0c7fbb1d7a76 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -33,7 +33,7 @@ impl Future for Ready { /// # Examples /// /// ``` -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let a = future::ready(1); diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 34a974b827158..03bb849509ad4 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -189,7 +189,7 @@ impl<'a> Location<'a> { /// # Examples /// /// ``` - /// use core::panic::Location; + /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. /// #[track_caller] diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index e221aaf3fd6d6..cbf6990001589 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,15 +1,18 @@ -/// Extracts the successful type of a `Poll`. +/// Extracts the successful type of a [`Poll`]. /// -/// This macro bakes in propagation of `Pending` signals by returning early. +/// This macro bakes in propagation of [`Pending`] signals by returning early. +/// +/// [`Poll`]: crate::task::Poll +/// [`Pending`]: crate::task::Poll::Pending /// /// # Examples /// /// ``` /// #![feature(ready_macro)] /// -/// use core::task::{ready, Context, Poll}; -/// use core::future::{self, Future}; -/// use core::pin::Pin; +/// use std::task::{ready, Context, Poll}; +/// use std::future::{self, Future}; +/// use std::pin::Pin; /// /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// let mut fut = future::ready(42); @@ -28,9 +31,9 @@ /// ``` /// # #![feature(ready_macro)] /// # -/// # use core::task::{Context, Poll}; -/// # use core::future::{self, Future}; -/// # use core::pin::Pin; +/// # use std::task::{Context, Poll}; +/// # use std::future::{self, Future}; +/// # use std::pin::Pin; /// # /// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// # let mut fut = future::ready(42); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 83eb847697dd4..6c240cb4c3ed9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,6 +212,7 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] +#![deny(rustc::existing_doc_keyword)] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 83a282c8cd6b5..55171ef2292d7 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -198,7 +198,7 @@ mod prim_bool {} /// words, they can't return `!` from every code path. As an example, this code doesn't compile: /// /// ```compile_fail -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// unimplemented!() @@ -208,7 +208,7 @@ mod prim_bool {} /// But this code does: /// /// ``` -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// if true { diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index 0e55ec648c9c5..76056637a4cf9 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,6 +1,5 @@ use std::env::*; use std::ffi::{OsStr, OsString}; -use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -92,6 +91,8 @@ fn env_home_dir() { cfg_if::cfg_if! { if #[cfg(unix)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); set_var("HOME", "/home/MountainView"); @@ -109,6 +110,8 @@ fn env_home_dir() { if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } } else if #[cfg(windows)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); let olduserprofile = var_to_os_string(var("USERPROFILE")); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a3c28be313792..8c344338de7a5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1000,7 +1000,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map_or(String::new(), |name| name.to_string()), + name: names.next().map_or_else(|| String::new(), |name| name.to_string()), }) .collect(), }, @@ -1974,16 +1974,13 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean> for (&hir::Item<'_>, Option) { +impl Clean> for (&hir::Item<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); - let mut name = match renamed { - Some(ident) => ident.name, - None => cx.tcx.hir().name(item.hir_id), - }; + let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id)); cx.with_param_env(def_id, || { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => StaticItem(Static { @@ -2276,7 +2273,7 @@ impl Clean> for doctree::Import<'_> { } } -impl Clean for (&hir::ForeignItem<'_>, Option) { +impl Clean for (&hir::ForeignItem<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; cx.with_param_env(cx.tcx.hir().local_def_id(item.hir_id).to_def_id(), || { @@ -2310,7 +2307,7 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { Item::from_hir_id_and_parts( item.hir_id, - Some(renamed.unwrap_or(item.ident).name), + Some(renamed.unwrap_or(item.ident.name)), kind, cx, ) @@ -2318,10 +2315,10 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { } } -impl Clean for (&hir::MacroDef<'_>, Option) { +impl Clean for (&hir::MacroDef<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; - let name = renamed.unwrap_or(item.ident).name; + let name = renamed.unwrap_or(item.ident.name); let tts = item.ast.body.inner_tokens().trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect::>(); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index eecdc929ab6fd..9c693c290e7f4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,6 @@ use rustc_hir::{ }; use rustc_interface::interface; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 3961870a1bfad..ee9a698185799 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -3,7 +3,7 @@ crate use self::StructType::*; use rustc_ast as ast; -use rustc_span::{self, symbol::Ident, Span, Symbol}; +use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -16,9 +16,9 @@ crate struct Module<'hir> { crate mods: Vec>, crate id: hir::HirId, // (item, renamed) - crate items: Vec<(&'hir hir::Item<'hir>, Option)>, - crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, - crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, + crate items: Vec<(&'hir hir::Item<'hir>, Option)>, + crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, + crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, crate is_crate: bool, } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c3153f2d4b6ff..e82bc540e95af 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -14,13 +14,13 @@ use crate::config::RenderInfo; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; +use crate::html::markdown::short_markdown_summary; use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; -use crate::html::render::{plain_text_summary, shorten}; thread_local!(crate static CACHE_KEY: RefCell> = Default::default()); -/// This cache is used to store information about the `clean::Crate` being +/// This cache is used to store information about the [`clean::Crate`] being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, /// documentation for all known traits, etc. @@ -313,7 +313,9 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item + .doc_value() + .map_or_else(|| String::new(), short_markdown_summary), parent, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ce686c65502f..0e4c5410abe1e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -17,8 +17,6 @@ //! // ... something using html //! ``` -#![allow(non_camel_case_types)] - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_hir::HirId; @@ -1037,7 +1035,95 @@ impl MarkdownSummaryLine<'_> { } } +/// Renders a subset of Markdown in the first paragraph of the provided Markdown. +/// +/// - *Italics*, **bold**, and `inline code` styles **are** rendered. +/// - Headings and links are stripped (though the text *is* rendered). +/// - HTML, code blocks, and everything else are ignored. +/// +/// Returns a tuple of the rendered HTML string and whether the output was shortened +/// due to the provided `length_limit`. +fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) { + if md.is_empty() { + return (String::new(), false); + } + + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut text_length = 0; + let mut stopped_early = false; + + fn push(s: &mut String, text_length: &mut usize, text: &str) { + s.push_str(text); + *text_length += text.len(); + }; + + 'outer: for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + match &event { + Event::Text(text) => { + for word in text.split_inclusive(char::is_whitespace) { + if text_length + word.len() >= length_limit { + stopped_early = true; + break 'outer; + } + + push(&mut s, &mut text_length, word); + } + } + Event::Code(code) => { + if text_length + code.len() >= length_limit { + stopped_early = true; + break; + } + + s.push_str(""); + push(&mut s, &mut text_length, code); + s.push_str(""); + } + Event::Start(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::CodeBlock(..) => break, + _ => {} + }, + Event::End(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::Paragraph => break, + _ => {} + }, + Event::HardBreak | Event::SoftBreak => { + if text_length + 1 >= length_limit { + stopped_early = true; + break; + } + + push(&mut s, &mut text_length, " "); + } + _ => {} + } + } + + (s, stopped_early) +} + +/// Renders a shortened first paragraph of the given Markdown as a subset of Markdown, +/// making it suitable for contexts like the search index. +/// +/// Will shorten to 59 or 60 characters, including an ellipsis (…) if it was shortened. +/// +/// See [`markdown_summary_with_limit`] for details about what is rendered and what is not. +crate fn short_markdown_summary(markdown: &str) -> String { + let (mut s, was_shortened) = markdown_summary_with_limit(markdown, 59); + + if was_shortened { + s.push('…'); + } + + s +} + /// Renders the first paragraph of the provided markdown as plain text. +/// Useful for alt-text. /// /// - Headings, links, and formatting are stripped. /// - Inline code is rendered as-is, surrounded by backticks. diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 8e618733f078e..9807d8632c75d 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::plain_text_summary; +use super::{plain_text_summary, short_markdown_summary}; use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use std::cell::RefCell; @@ -204,6 +204,33 @@ fn test_header_ids_multiple_blocks() { ); } +#[test] +fn test_short_markdown_summary() { + fn t(input: &str, expect: &str) { + let output = short_markdown_summary(input); + assert_eq!(output, expect, "original: {}", input); + } + + t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("*italic*", "italic"); + t("**bold**", "bold"); + t("Multi-line\nsummary", "Multi-line summary"); + t("Hard-break \nsummary", "Hard-break summary"); + t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); + t("code `let x = i32;` ...", "code let x = i32; ..."); + t("type `Type<'static>` ...", "type Type<'static> ..."); + t("# top header", "top header"); + t("## header", "header"); + t("first paragraph\n\nsecond paragraph", "first paragraph"); + t("```\nfn main() {}\n```", ""); + t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of …", + ); +} + #[test] fn test_plain_text_summary() { fn t(input: &str, expect: &str) { @@ -224,6 +251,10 @@ fn test_plain_text_summary() { t("first paragraph\n\nsecond paragraph", "first paragraph"); t("```\nfn main() {}\n```", ""); t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of `inline code: Vec`. and it has a link. that was a soft line break! that was a hard one", + ); } #[test] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 085ca01f58daa..97f764517faf6 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,7 +9,7 @@ use crate::clean::types::GetDefId; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::{plain_text_summary, shorten}; +use crate::html::markdown::short_markdown_summary; use crate::html::render::{Generic, IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. @@ -78,7 +78,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item.doc_value().map_or_else(|| String::new(), short_markdown_summary), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -127,7 +127,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let crate_doc = krate .module .as_ref() - .map(|module| shorten(plain_text_summary(module.doc_value()))) + .map(|module| module.doc_value().map_or_else(|| String::new(), short_markdown_summary)) .unwrap_or_default(); #[derive(Serialize)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index de620a35c80d7..901f00b21da9d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -76,7 +76,9 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::format::Function; use crate::html::format::{href, print_default_space, print_generic_bounds, WhereClause}; use crate::html::format::{print_abi_with_space, Buffer, PrintWithSpace}; -use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{ + self, plain_text_summary, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine, +}; use crate::html::sources; use crate::html::{highlight, layout, static_files}; use cache::{build_index, ExternalLocation}; @@ -1604,9 +1606,10 @@ impl Context { Some(ref s) => s.to_string(), }; let short = short.to_string(); - map.entry(short) - .or_default() - .push((myname, Some(plain_text_summary(item.doc_value())))); + map.entry(short).or_default().push(( + myname, + Some(item.doc_value().map_or_else(|| String::new(), plain_text_summary)), + )); } if self.shared.sort_modules_alphabetically { @@ -1810,36 +1813,6 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -/// Renders the first paragraph of the given markdown as plain text, making it suitable for -/// contexts like alt-text or the search index. -/// -/// If no markdown is supplied, the empty string is returned. -/// -/// See [`markdown::plain_text_summary`] for further details. -#[inline] -crate fn plain_text_summary(s: Option<&str>) -> String { - s.map(markdown::plain_text_summary).unwrap_or_default() -} - -crate fn shorten(s: String) -> String { - if s.chars().count() > 60 { - let mut len = 0; - let mut ret = s - .split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::>() - .join(" "); - ret.push('…'); - ret - } else { - s - } -} - fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 69984be5eb622..0884351a9fd80 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1611,7 +1611,7 @@ function defocusSearchBar() { item.displayPath + "" + name + "" + "" + - "" + escape(item.desc) + + "" + item.desc + " "; }); output += ""; @@ -2013,7 +2013,9 @@ function defocusSearchBar() { } var link = document.createElement("a"); link.href = rootPath + crates[i] + "/index.html"; - link.title = rawSearchIndex[crates[i]].doc; + // The summary in the search index has HTML, so we need to + // dynamically render it as plaintext. + link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc); link.className = klass; link.textContent = crates[i]; @@ -2026,6 +2028,23 @@ function defocusSearchBar() { } }; + /** + * Convert HTML to plaintext: + * + * * Replace "foo" with "`foo`" + * * Strip all other HTML tags + * + * Used by the dynamic sidebar crate list renderer. + * + * @param {[string]} html [The HTML to convert] + * @return {[string]} [The resulting plaintext] + */ + function convertHTMLToPlaintext(html) { + var x = document.createElement("div"); + x.innerHTML = html.replace('', '`').replace('', '`'); + return x.innerText; + } + // delayed sidebar rendering. window.initSidebarItems = function(items) { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 80a9c3811cf66..26bf4b569ff4b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,6 +15,7 @@ #![feature(never_type)] #![feature(once_cell)] #![feature(type_ascription)] +#![feature(split_inclusive)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3dcc0f240a3f8..551c086a8d4e3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -847,12 +847,17 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly let self_name = self_id.and_then(|self_id| { + use ty::TyKind; if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) { - // using `ty.to_string()` directly has issues with shortening paths + // using `ty.to_string()` (or any variant) has issues with raw idents let ty = self.cx.tcx.type_of(self_id); - let name = ty::print::with_crate_prefix(|| ty.to_string()); - debug!("using type_of(): {}", name); - Some(name) + let name = match ty.kind() { + TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()), + other if other.is_primitive() => Some(ty.to_string()), + _ => None, + }; + debug!("using type_of(): {:?}", name); + name } else { let name = self.cx.tcx.opt_item_name(self_id).map(|sym| sym.to_string()); debug!("using item_name(): {:?}", name); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4028293076df9..f9cb1d586b102 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,7 +10,7 @@ use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{self, Span}; use std::mem; @@ -116,7 +116,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &mut self, id: hir::HirId, res: Res, - renamed: Option, + renamed: Option, glob: bool, om: &mut Module<'tcx>, please_inline: bool, @@ -226,11 +226,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_item( &mut self, item: &'tcx hir::Item<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { debug!("visiting item {:?}", item); - let ident = renamed.unwrap_or(item.ident); + let name = renamed.unwrap_or(item.ident.name); if item.vis.node.is_pub() { let def_id = self.cx.tcx.hir().local_def_id(item.hir_id); @@ -266,7 +266,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } _ => false, }); - let ident = if is_glob { None } else { Some(ident) }; + let ident = if is_glob { None } else { Some(name) }; if self.maybe_inline_local( item.hir_id, path.res, @@ -280,7 +280,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } om.imports.push(Import { - name: ident.name, + name, id: item.hir_id, vis: &item.vis, attrs: &item.attrs, @@ -296,7 +296,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &item.vis, item.hir_id, m, - Some(ident.name), + Some(name), )); } hir::ItemKind::Fn(..) @@ -312,7 +312,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. - if ident.name != kw::Underscore { + if name != kw::Underscore { om.items.push((item, renamed)); } } @@ -329,7 +329,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_foreign_item( &mut self, item: &'tcx hir::ForeignItem<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs index 1b4963fcebea8..da946a58b1c88 100644 --- a/src/test/rustdoc-js/basic.rs +++ b/src/test/rustdoc-js/basic.rs @@ -1,2 +1,2 @@ -/// Foo +/// Docs for Foo pub struct Foo; diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js new file mode 100644 index 0000000000000..f175e47342df6 --- /dev/null +++ b/src/test/rustdoc-js/summaries.js @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2']; + +const EXPECTED = [ + { + 'others': [ + { 'path': '', 'name': 'summaries', 'desc': 'This summary has a link and code.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar', 'desc': 'This code will be rendered in a code tag.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar2', 'desc': '' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs new file mode 100644 index 0000000000000..beb91e286b610 --- /dev/null +++ b/src/test/rustdoc-js/summaries.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This *summary* has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +/// This `code` will be rendered in a code tag. +/// +/// This text should not be rendered. +pub struct Sidebar; + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs new file mode 100644 index 0000000000000..d289797f14652 --- /dev/null +++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs @@ -0,0 +1,13 @@ +#![deny(broken_intra_doc_links)] +pub mod r#impl { + pub struct S; + + impl S { + /// See [Self::b]. + // @has raw_ident_self/impl/struct.S.html + // @has - '//a[@href="../../raw_ident_self/impl/struct.S.html#method.b"]' 'Self::b' + pub fn a() {} + + pub fn b() {} + } +} diff --git a/src/test/rustdoc/plain-text-summaries.rs b/src/test/rustdoc/markdown-summaries.rs similarity index 55% rename from src/test/rustdoc/plain-text-summaries.rs rename to src/test/rustdoc/markdown-summaries.rs index c995ccbf0af67..b843e28e7b0d3 100644 --- a/src/test/rustdoc/plain-text-summaries.rs +++ b/src/test/rustdoc/markdown-summaries.rs @@ -1,21 +1,22 @@ #![crate_type = "lib"] #![crate_name = "summaries"] -//! This summary has a [link] and `code`. +//! This *summary* has a [link] and `code`. //! //! This is the second paragraph. //! //! [link]: https://example.com -// @has search-index.js 'This summary has a link and `code`.' +// @has search-index.js 'This summary has a link and code.' // @!has - 'second paragraph' -/// This `code` should be in backticks. +/// This `code` will be rendered in a code tag. /// /// This text should not be rendered. pub struct Sidebar; -// @has summaries/sidebar-items.js 'This `code` should be in backticks.' +// @has search-index.js 'This code will be rendered in a code tag.' +// @has summaries/sidebar-items.js 'This `code` will be rendered in a code tag.' // @!has - 'text should not be rendered' /// ```text diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs new file mode 100644 index 0000000000000..053712a4b4ee6 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs @@ -0,0 +1,11 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![feature(doc_keyword)] + +#![crate_type = "lib"] + +#![deny(rustc::existing_doc_keyword)] + +#[doc(keyword = "tadam")] //~ ERROR +mod tadam {} diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr new file mode 100644 index 0000000000000..bac44f338b74c --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -0,0 +1,15 @@ +error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` + --> $DIR/existing_doc_keyword.rs:10:1 + | +LL | #[doc(keyword = "tadam")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/existing_doc_keyword.rs:8:9 + | +LL | #![deny(rustc::existing_doc_keyword)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: only existing keywords are allowed in core/std + +error: aborting due to previous error + diff --git a/src/tools/cargo b/src/tools/cargo index bfca1cd22bf51..63d0fe43449ad 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit bfca1cd22bf514d5f2b6c1089b0ded0ba7dfaa6e +Subproject commit 63d0fe43449adcb316d34d98a982b597faca4178