diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 2a0f4fdc77412..c21e4acbefec0 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -341,14 +341,12 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, unsigned Index, LLVMRustAttribute RustAttr) { Function *F = unwrap(Fn); - Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); - AttrBuilder B(Attr); - auto PAL = F->getAttributes(); + AttributeList PAL = F->getAttributes(); AttributeList PALNew; #if LLVM_VERSION_LT(14, 0) - PALNew = PAL.removeAttributes(F->getContext(), Index, B); + PALNew = PAL.removeAttribute(F->getContext(), Index, fromRust(RustAttr)); #else - PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B); + PALNew = PAL.removeAttributeAtIndex(F->getContext(), Index, fromRust(RustAttr)); #endif F->setAttributes(PALNew); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8ff3b1e72d804..bb9a58a0b62aa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -27,6 +27,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::cstore::{ @@ -92,8 +93,7 @@ crate struct CrateMetadata { /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. - trait_impls: - FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option)]>>, + trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option)]>>, /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. @@ -722,25 +722,24 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { &self.raw_proc_macros.unwrap()[pos] } - fn try_item_ident(&self, item_index: DefIndex, sess: &Session) -> Result { - let name = self - .def_key(item_index) - .disambiguated_data - .data - .get_opt_name() - .ok_or_else(|| format!("Missing opt name for {:?}", item_index))?; - let span = self - .root - .tables - .ident_span - .get(self, item_index) - .ok_or_else(|| format!("Missing ident span for {:?} ({:?})", name, item_index))? - .decode((self, sess)); - Ok(Ident::new(name, span)) + fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option { + let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?; + let span = match self.root.tables.ident_span.get(self, item_index) { + Some(lazy_span) => lazy_span.decode((self, sess)), + None => { + // FIXME: this weird case of a name with no span is specific to `extern crate` + // items, which are supposed to be treated like `use` items and only be encoded + // to metadata as `Export`s, return `None` because that's what all the callers + // expect in this case. + assert_eq!(self.def_kind(item_index), DefKind::ExternCrate); + return None; + } + }; + Some(Ident::new(name, span)) } fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident { - self.try_item_ident(item_index, sess).unwrap() + self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } fn maybe_kind(&self, item_id: DefIndex) -> Option { @@ -1102,27 +1101,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // Iterate over all children. if let Some(children) = self.root.tables.children.get(self, id) { for child_index in children.decode((self, sess)) { - // FIXME: Merge with the logic below. - if let None | Some(EntryKind::ForeignMod | EntryKind::Impl(_)) = - self.maybe_kind(child_index) - { - continue; - } - - let def_key = self.def_key(child_index); - if def_key.disambiguated_data.data.get_opt_name().is_some() { - let span = self.get_span(child_index, sess); + if let Some(ident) = self.opt_item_ident(child_index, sess) { let kind = self.def_kind(child_index); - let ident = self.item_ident(child_index, sess); - let vis = self.get_visibility(child_index); + if matches!(kind, DefKind::Macro(..)) { + // FIXME: Macros are currently encoded twice, once as items and once as + // reexports. We ignore the items here and only use the reexports. + continue; + } let def_id = self.local_def_id(child_index); let res = Res::Def(kind, def_id); + let vis = self.get_visibility(child_index); + let span = self.get_span(child_index, sess); - // FIXME: Macros are currently encoded twice, once as items and once as - // reexports. We ignore the items here and only use the reexports. - if !matches!(kind, DefKind::Macro(..)) { - callback(Export { res, ident, vis, span }); - } + callback(Export { ident, res, vis, span }); // For non-re-export structs and variants add their constructors to children. // Re-export lists automatically contain constructors when necessary. @@ -1309,24 +1300,26 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_item_attrs( &'a self, - node_id: DefIndex, + id: DefIndex, sess: &'a Session, ) -> impl Iterator + 'a { - // The attributes for a tuple struct/variant are attached to the definition, not the ctor; - // we assume that someone passing in a tuple struct ctor is actually wanting to - // look at the definition - let def_key = self.def_key(node_id); - let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor { - def_key.parent.unwrap() - } else { - node_id - }; - self.root .tables .attributes - .get(self, item_id) - .unwrap_or_else(Lazy::empty) + .get(self, id) + .unwrap_or_else(|| { + // Structure and variant constructors don't have any attributes encoded for them, + // but we assume that someone passing a constructor ID actually wants to look at + // the attributes on the corresponding struct or variant. + let def_key = self.def_key(id); + assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor); + let parent_id = def_key.parent.expect("no parent for a constructor"); + self.root + .tables + .attributes + .get(self, parent_id) + .expect("no encoded attributes for a structure or variant") + }) .decode((self, sess)) } @@ -1372,39 +1365,39 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.traits.decode(self).map(|index| self.local_def_id(index)) } - fn get_implementations_for_trait( + fn get_trait_impls(&'a self) -> impl Iterator)> + 'a { + self.trait_impls.values().flat_map(move |impls| { + impls + .decode(self) + .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + }) + } + + fn get_implementations_of_trait( &self, tcx: TyCtxt<'tcx>, - filter: Option, - ) -> &'tcx [(DefId, Option)] { + trait_def_id: DefId, + ) -> &'tcx [(DefId, Option)] { if self.root.is_proc_macro_crate() { // proc-macro crates export no trait impls. return &[]; } - if let Some(def_id) = filter { - // Do a reverse lookup beforehand to avoid touching the crate_num - // hash map in the loop below. - let filter = match self.reverse_translate_def_id(def_id) { - Some(def_id) => (def_id.krate.as_u32(), def_id.index), - None => return &[], - }; + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + let key = match self.reverse_translate_def_id(trait_def_id) { + Some(def_id) => (def_id.krate.as_u32(), def_id.index), + None => return &[], + }; - if let Some(impls) = self.trait_impls.get(&filter) { - tcx.arena.alloc_from_iter( - impls.decode(self).map(|(idx, simplified_self_ty)| { - (self.local_def_id(idx), simplified_self_ty) - }), - ) - } else { - &[] - } - } else { - tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| { + if let Some(impls) = self.trait_impls.get(&key) { + tcx.arena.alloc_from_iter( impls .decode(self) - .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) - })) + .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)), + ) + } else { + &[] } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7ffc586fda3a5..aac0aa61ea65e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -133,9 +133,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, generator_kind => { cdata.generator_kind(def_id.index) } opt_def_kind => { Some(cdata.def_kind(def_id.index)) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } - def_ident_span => { - cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span) - } + def_ident_span => { cdata.opt_item_ident(def_id.index, &tcx.sess).map(|ident| ident.span) } lookup_stability => { cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s)) } @@ -145,9 +143,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, lookup_deprecation_entry => { cdata.get_deprecation(def_id.index).map(DeprecationEntry::external) } - item_attrs => { tcx.arena.alloc_from_iter( - cdata.get_item_attrs(def_id.index, tcx.sess) - ) } + item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } @@ -196,14 +192,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } - implementations_of_trait => { - cdata.get_implementations_for_trait(tcx, Some(other)) - } - - all_trait_implementations => { - cdata.get_implementations_for_trait(tcx, None) - } + implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } visibility => { cdata.get_visibility(def_id.index) } dep_kind => { @@ -470,7 +461,7 @@ impl CStore { self.get_crate_data(cnum).num_def_ids() } - pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec { + pub fn item_attrs_untracked(&self, def_id: DefId, sess: &Session) -> Vec { self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3942846e79df0..12d66f4fc45f3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::interpret; use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; -use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; @@ -2055,7 +2055,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { struct ImplsVisitor<'tcx> { tcx: TyCtxt<'tcx>, - impls: FxHashMap)>>, + impls: FxHashMap)>>, } impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 35016453369b5..4076e0b9e0fed 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::thir; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; @@ -261,7 +262,7 @@ crate struct CrateDep { #[derive(MetadataEncodable, MetadataDecodable)] crate struct TraitImpls { trait_id: (u32, DefIndex), - impls: Lazy<[(DefIndex, Option)]>, + impls: Lazy<[(DefIndex, Option)]>, } /// Define `LazyTables` and `TableBuilders` at the same time. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 027c0c64924b8..b3db2e6340024 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1411,16 +1411,14 @@ rustc_queries! { /// Given a crate and a trait, look up all impls of that trait in the crate. /// Return `(impl_id, self_ty)`. - query implementations_of_trait(_: (CrateNum, DefId)) - -> &'tcx [(DefId, Option)] { + query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option)] { desc { "looking up implementations of a trait in a crate" } separate_provide_extern } /// Given a crate, look up all trait impls in that crate. /// Return `(impl_id, self_ty)`. - query all_trait_implementations(_: CrateNum) - -> &'tcx [(DefId, Option)] { + query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option)] { desc { "looking up all (?) trait implementations" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 04011552e31ed..daf9156a15f34 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -143,6 +143,18 @@ pub fn simplify_type( } impl SimplifiedTypeGen { + pub fn def(self) -> Option { + match self { + AdtSimplifiedType(d) + | ForeignSimplifiedType(d) + | TraitSimplifiedType(d) + | ClosureSimplifiedType(d) + | GeneratorSimplifiedType(d) + | OpaqueSimplifiedType(d) => Some(d), + _ => None, + } + } + pub fn map_def(self, map: F) -> SimplifiedTypeGen where F: Fn(D) -> U, diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2f91503afdfaf..3af1b3a044024 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -28,6 +28,7 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{self, ImplSource}; +use crate::ty::fast_reject::SimplifiedType; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index cbb88def7e27d..34d059f4ec849 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; use crate::ty::fold::TypeFoldable; use crate::ty::{Ty, TyCtxt}; use rustc_hir as hir; @@ -68,7 +68,7 @@ pub enum TraitSpecializationKind { pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxIndexMap>, + non_blanket_impls: FxIndexMap>, } impl TraitImpls { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index babfa8015af6c..4feeae5cab1de 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -895,8 +895,11 @@ impl<'a> Resolver<'a> { // a note about editions let note = if let Some(did) = did { let requires_note = !did.is_local() - && this.cstore().item_attrs(did, this.session).iter().any( - |attr| { + && this + .cstore() + .item_attrs_untracked(did, this.session) + .iter() + .any(|attr| { if attr.has_name(sym::rustc_diagnostic_item) { [sym::TryInto, sym::TryFrom, sym::FromIterator] .map(|x| Some(x)) @@ -904,8 +907,7 @@ impl<'a> Resolver<'a> { } else { false } - }, - ); + }); requires_note.then(|| { format!( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2008570d6f0ef..b46a93c06734b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -3420,7 +3420,7 @@ impl<'a> Resolver<'a> { let attr = self .cstore() - .item_attrs(def_id, self.session) + .item_attrs_untracked(def_id, self.session) .into_iter() .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; let mut ret = Vec::new(); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e1fef84d9d929..41c8a37a71a6d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -295,7 +295,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { if let hir::ExprKind::Closure(..) = expr.kind { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().type_of(def_id); + // We do not call `type_of` for closures here as that + // depends on typecheck and would therefore hide + // any further errors in case one typeck fails. } intravisit::walk_expr(self, expr); } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 04e887bf7420f..ae8d262fcf176 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -470,14 +470,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - if let Some(movability) = gen { - tcx.mk_generator(def_id.to_def_id(), substs, movability) - } else { - tcx.mk_closure(def_id.to_def_id(), substs) - } - } + Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id), Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { // We defer to `type_of` of the corresponding parameter diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 32b4018f626b2..1ae0ff3036471 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -715,13 +715,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_captures({:?})", closure_expr); - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); - let upvars = self.tcx().upvars_mentioned(self.body_owner); + let tcx = self.tcx(); + let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id(); + let upvars = tcx.upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. let body_owner_is_closure = matches!( - self.tcx().type_of(self.body_owner.to_def_id()).kind(), - ty::Closure(..) | ty::Generator(..) + tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)), + hir::BodyOwnerKind::Closure, ); // If we have a nested closure, we want to include the fake reads present in the nested closure. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6fdaa8b950aa1..3ad48a1d283d8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2277,16 +2277,6 @@ impl ExtendWith for ExtendElement { } } -struct ExtendDefault; -impl ExtendWith for ExtendDefault { - fn next(&mut self) -> T { - Default::default() - } - fn last(self) -> T { - Default::default() - } -} - struct ExtendFunc(F); impl T> ExtendWith for ExtendFunc { fn next(&mut self) -> T { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5235a6b818053..7c36bb264c45e 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -13,7 +13,7 @@ import tarfile import tempfile -from time import time +from time import time, sleep # Acquire a lock on the build directory to make sure that # we don't cause a race condition while building @@ -42,8 +42,10 @@ def acquire_lock(build_dir): while True: try: curs.execute("BEGIN EXCLUSIVE") + break except sqlite3.OperationalError: pass + sleep(0.25) return curs except ImportError: print("warning: sqlite3 not available in python, skipping build directory lock") diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f0f61bb94c8e8..f278c6c17bbba 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,6 +1,5 @@ use std::cell::RefCell; use std::default::Default; -use std::fmt::Write; use std::hash::Hash; use std::lazy::SyncOnceCell as OnceCell; use std::path::PathBuf; @@ -496,7 +495,7 @@ impl Item { if let Ok((mut href, ..)) = href(*did, cx) { debug!(?href); if let Some(ref fragment) = *fragment { - write!(href, "{}", fragment).unwrap() + fragment.render(&mut href, cx.tcx()).unwrap() } Some(RenderedLink { original_text: s.clone(), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7953008628204..0069f438270c3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -13,7 +13,7 @@ use rustc_hir::def::{ PerNS, }; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{DefIdTree, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::Lint; @@ -25,8 +25,8 @@ use smallvec::{smallvec, SmallVec}; use pulldown_cmark::LinkType; use std::borrow::Cow; -use std::cell::Cell; use std::convert::{TryFrom, TryInto}; +use std::fmt::Write; use std::mem; use std::ops::Range; @@ -47,12 +47,8 @@ crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut collector = LinkCollector { - cx, - mod_ids: Vec::new(), - kind_side_channel: Cell::new(None), - visited_links: FxHashMap::default(), - }; + let mut collector = + LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() }; collector.visit_crate(&krate); krate } @@ -240,53 +236,73 @@ enum AnchorFailure { #[derive(Clone, Debug, Hash, PartialEq, Eq)] crate enum UrlFragment { - Method(Symbol), - TyMethod(Symbol), - AssociatedConstant(Symbol), - AssociatedType(Symbol), - - StructField(Symbol), - Variant(Symbol), - VariantField { variant: Symbol, field: Symbol }, - + Item(ItemFragment), UserWritten(String), } impl UrlFragment { + /// Render the fragment, including the leading `#`. + crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result { + match self { + UrlFragment::Item(frag) => frag.render(s, tcx), + UrlFragment::UserWritten(raw) => write!(s, "#{}", raw), + } + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +crate struct ItemFragment(FragmentKind, DefId); + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +crate enum FragmentKind { + Method, + TyMethod, + AssociatedConstant, + AssociatedType, + + StructField, + Variant, + VariantField, +} + +impl ItemFragment { /// Create a fragment for an associated item. /// /// `is_prototype` is whether this associated item is a trait method /// without a default definition. - fn from_assoc_item(name: Symbol, kind: ty::AssocKind, is_prototype: bool) -> Self { + fn from_assoc_item(def_id: DefId, kind: ty::AssocKind, is_prototype: bool) -> Self { match kind { ty::AssocKind::Fn => { if is_prototype { - UrlFragment::TyMethod(name) + ItemFragment(FragmentKind::TyMethod, def_id) } else { - UrlFragment::Method(name) + ItemFragment(FragmentKind::Method, def_id) } } - ty::AssocKind::Const => UrlFragment::AssociatedConstant(name), - ty::AssocKind::Type => UrlFragment::AssociatedType(name), + ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id), + ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id), } } -} -/// Render the fragment, including the leading `#`. -impl std::fmt::Display for UrlFragment { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "#")?; - match self { - UrlFragment::Method(name) => write!(f, "method.{}", name), - UrlFragment::TyMethod(name) => write!(f, "tymethod.{}", name), - UrlFragment::AssociatedConstant(name) => write!(f, "associatedconstant.{}", name), - UrlFragment::AssociatedType(name) => write!(f, "associatedtype.{}", name), - UrlFragment::StructField(name) => write!(f, "structfield.{}", name), - UrlFragment::Variant(name) => write!(f, "variant.{}", name), - UrlFragment::VariantField { variant, field } => { - write!(f, "variant.{}.field.{}", variant, field) + /// Render the fragment, including the leading `#`. + crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result { + write!(s, "#")?; + match *self { + ItemFragment(kind, def_id) => { + let name = tcx.item_name(def_id); + match kind { + FragmentKind::Method => write!(s, "method.{}", name), + FragmentKind::TyMethod => write!(s, "tymethod.{}", name), + FragmentKind::AssociatedConstant => write!(s, "associatedconstant.{}", name), + FragmentKind::AssociatedType => write!(s, "associatedtype.{}", name), + FragmentKind::StructField => write!(s, "structfield.{}", name), + FragmentKind::Variant => write!(s, "variant.{}", name), + FragmentKind::VariantField => { + let variant = tcx.item_name(tcx.parent(def_id).unwrap()); + write!(s, "variant.{}.field.{}", variant, name) + } + } } - UrlFragment::UserWritten(raw) => write!(f, "{}", raw), } } } @@ -296,7 +312,7 @@ struct ResolutionInfo { module_id: DefId, dis: Option, path_str: String, - extra_fragment: Option, + extra_fragment: Option, } #[derive(Clone)] @@ -310,7 +326,6 @@ struct DiagnosticInfo<'a> { #[derive(Clone, Debug, Hash)] struct CachedLink { pub res: (Res, Option), - pub side_channel: Option<(DefKind, DefId)>, } struct LinkCollector<'a, 'tcx> { @@ -320,10 +335,6 @@ struct LinkCollector<'a, 'tcx> { /// The last module will be used if the parent scope of the current item is /// unknown. mod_ids: Vec, - /// This is used to store the kind of associated items, - /// because `clean` and the disambiguator code expect them to be different. - /// See the code for associated items on inherent impls for details. - kind_side_channel: Cell>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). visited_links: FxHashMap>, @@ -340,7 +351,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &'path str, module_id: DefId, - ) -> Result<(Res, Option), ErrorKind<'path>> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let tcx = self.cx.tcx; let no_res = || ResolutionFailure::NotResolved { module_id, @@ -387,14 +398,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } match tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { - if def.all_fields().any(|item| item.ident.name == variant_field_name) { - Ok(( - ty_res, - Some(UrlFragment::VariantField { - variant: variant_name, - field: variant_field_name, - }), - )) + if let Some(field) = + def.all_fields().find(|f| f.ident.name == variant_field_name) + { + Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did)))) } else { Err(ResolutionFailure::NotResolved { module_id, @@ -422,7 +429,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { prim_ty: PrimitiveType, ns: Namespace, item_name: Symbol, - ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> { + ) -> Option<(Res, ItemFragment)> { let tcx = self.cx.tcx; prim_ty.impls(tcx).into_iter().find_map(|&impl_| { @@ -430,8 +437,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_) .map(|item| { let kind = item.kind; - let fragment = UrlFragment::from_assoc_item(item_name, kind, false); - (Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id))) + let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + (Res::Primitive(prim_ty), fragment) }) }) } @@ -505,8 +512,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &'path str, ns: Namespace, module_id: DefId, - extra_fragment: &Option, + user_fragment: &Option, ) -> Result<(Res, Option), ErrorKind<'path>> { + let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?; + let chosen_fragment = match (user_fragment, rustdoc_fragment) { + (Some(_), Some(r_frag)) => { + let diag_res = match r_frag { + ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did), + }; + let failure = AnchorFailure::RustdocAnchorConflict(diag_res); + return Err(ErrorKind::AnchorFailure(failure)); + } + (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())), + (None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)), + (None, None) => None, + }; + Ok((res, chosen_fragment)) + } + + fn resolve_inner<'path>( + &mut self, + path_str: &'path str, + ns: Namespace, + module_id: DefId, + ) -> Result<(Res, Option), ErrorKind<'path>> { if let Some(res) = self.resolve_path(path_str, ns, module_id) { match res { // FIXME(#76467): make this fallthrough to lookup the associated @@ -514,10 +543,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS), Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS), Res::Def(DefKind::Variant, _) => { - return handle_variant(self.cx, res, extra_fragment); + return handle_variant(self.cx, res); } // Not a trait item; just return what we found. - _ => return Ok((res, extra_fragment.clone())), + _ => return Ok((res, None)), } } @@ -548,23 +577,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { resolve_primitive(&path_root, TypeNS) .or_else(|| self.resolve_path(&path_root, TypeNS, module_id)) .and_then(|ty_res| { - let (res, fragment, side_channel) = + let (res, fragment) = self.resolve_associated_item(ty_res, item_name, ns, module_id)?; - let result = if extra_fragment.is_some() { - // NOTE: can never be a primitive since `side_channel.is_none()` only when `res` - // is a trait (and the side channel DefId is always an associated item). - let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r)); - Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res))) - } else { - // HACK(jynelson): `clean` expects the type, not the associated item - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - if let Some((kind, id)) = side_channel { - self.kind_side_channel.set(Some((kind, id))); - } - Ok((res, Some(fragment))) - }; - Some(result) + + Some(Ok((res, Some(fragment)))) }) .unwrap_or_else(|| { if ns == Namespace::ValueNS { @@ -661,7 +677,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { item_name: Symbol, ns: Namespace, module_id: DefId, - ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> { + ) -> Option<(Res, ItemFragment)> { let tcx = self.cx.tcx; match root_res { @@ -676,11 +692,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { assoc_item.map(|item| { let kind = item.kind; - let fragment = UrlFragment::from_assoc_item(item_name, kind, false); - // HACK(jynelson): `clean` expects the type, not the associated item - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - (root_res, fragment, Some((kind.as_def_kind(), item.def_id))) + let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + (root_res, fragment) }) }) } @@ -730,11 +743,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if let Some(item) = assoc_item { let kind = item.kind; - let fragment = UrlFragment::from_assoc_item(item_name, kind, false); - // HACK(jynelson): `clean` expects the type, not the associated item - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - return Some((root_res, fragment, Some((kind.as_def_kind(), item.def_id)))); + let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false); + return Some((root_res, fragment)); } if ns != Namespace::ValueNS { @@ -765,23 +775,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .fields .iter() .find(|item| item.ident.name == item_name)?; - Some(( - root_res, - UrlFragment::StructField(field.ident.name), - Some((DefKind::Field, field.did)), - )) + Some((root_res, ItemFragment(FragmentKind::StructField, field.did))) } Res::Def(DefKind::Trait, did) => tcx .associated_items(did) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did) .map(|item| { - let fragment = UrlFragment::from_assoc_item( - item_name, + let fragment = ItemFragment::from_assoc_item( + item.def_id, item.kind, !item.defaultness.has_value(), ); let res = Res::Def(item.kind.as_def_kind(), item.def_id); - (res, fragment, None) + (res, fragment) }), _ => None, } @@ -798,23 +804,32 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ns: Namespace, path_str: &str, module_id: DefId, - extra_fragment: &Option, + extra_fragment: &Option, ) -> Option { // resolve() can't be used for macro namespace let result = match ns { - Namespace::MacroNS => self.resolve_macro(path_str, module_id).map_err(ErrorKind::from), + Namespace::MacroNS => self + .resolve_macro(path_str, module_id) + .map(|res| (res, None)) + .map_err(ErrorKind::from), Namespace::TypeNS | Namespace::ValueNS => { - self.resolve(path_str, ns, module_id, extra_fragment).map(|(res, _)| res) + self.resolve(path_str, ns, module_id, extra_fragment) } }; let res = match result { - Ok(res) => Some(res), + Ok((res, frag)) => { + if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag { + Some(Res::Def(self.cx.tcx.def_kind(id), id)) + } else { + Some(res) + } + } Err(ErrorKind::Resolve(box kind)) => kind.full_res(), Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res), Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, }; - self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + res } } @@ -912,8 +927,6 @@ fn is_derive_trait_collision(ns: &PerNS DocVisitor for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { - use rustc_middle::ty::DefIdTree; - let parent_node = item.def_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did)); if parent_node.is_some() { @@ -1033,7 +1046,7 @@ impl From for PreprocessingError<'_> { struct PreprocessingInfo { path_str: String, disambiguator: Option, - extra_fragment: Option, + extra_fragment: Option, link_text: String, } @@ -1119,7 +1132,7 @@ fn preprocess_link<'a>( Some(Ok(PreprocessingInfo { path_str, disambiguator, - extra_fragment: extra_fragment.map(|frag| UrlFragment::UserWritten(frag.to_owned())), + extra_fragment: extra_fragment.map(|frag| frag.to_owned()), link_text: link_text.to_owned(), })) } @@ -1286,7 +1299,11 @@ impl LinkCollector<'_, '_> { }; let verify = |kind: DefKind, id: DefId| { - let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id)); + let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { + (self.cx.tcx.def_kind(id), id) + } else { + (kind, id) + }; debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id); // Disallow e.g. linking to enums with `struct@` @@ -1330,7 +1347,9 @@ impl LinkCollector<'_, '_> { match res { Res::Primitive(prim) => { - if let Some((kind, id)) = self.kind_side_channel.take() { + if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { + let kind = self.cx.tcx.def_kind(id); + // We're actually resolving an associated item of a primitive, so we need to // verify the disambiguator (if any) matches the type of the associated item. // This case should really follow the same flow as the `Res::Def` branch below, @@ -1347,22 +1366,7 @@ impl LinkCollector<'_, '_> { && item.def_id.is_local() && !self.cx.tcx.features().intra_doc_pointers { - let span = super::source_span_for_markdown_range( - self.cx.tcx, - dox, - &ori_link.range, - &item.attrs, - ) - .unwrap_or_else(|| item.attr_span(self.cx.tcx)); - - rustc_session::parse::feature_err( - &self.cx.tcx.sess.parse_sess, - sym::intra_doc_pointers, - span, - "linking to associated items of raw pointers is experimental", - ) - .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does") - .emit(); + self.report_rawptr_assoc_feature_gate(dox, &ori_link, item); } } else { match disambiguator { @@ -1389,6 +1393,20 @@ impl LinkCollector<'_, '_> { } } + fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) { + let span = + super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs) + .unwrap_or_else(|| item.attr_span(self.cx.tcx)); + rustc_session::parse::feature_err( + &self.cx.tcx.sess.parse_sess, + sym::intra_doc_pointers, + span, + "linking to associated items of raw pointers is experimental", + ) + .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does") + .emit(); + } + fn resolve_with_disambiguator_cached( &mut self, key: ResolutionInfo, @@ -1399,7 +1417,6 @@ impl LinkCollector<'_, '_> { if let Some(ref cached) = self.visited_links.get(&key) { match cached { Some(cached) => { - self.kind_side_channel.set(cached.side_channel); return Some(cached.res.clone()); } None if cache_resolution_failure => return None, @@ -1416,13 +1433,7 @@ impl LinkCollector<'_, '_> { // Cache only if resolved successfully - don't silence duplicate errors if let Some(res) = res { // Store result for the actual namespace - self.visited_links.insert( - key, - Some(CachedLink { - res: res.clone(), - side_channel: self.kind_side_channel.clone().into_inner(), - }), - ); + self.visited_links.insert(key, Some(CachedLink { res: res.clone() })); Some(res) } else { @@ -1484,7 +1495,7 @@ impl LinkCollector<'_, '_> { let mut candidates = PerNS { macro_ns: self .resolve_macro(path_str, base_node) - .map(|res| (res, extra_fragment.clone())), + .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))), type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) { Ok(res) => { debug!("got res in TypeNS: {:?}", res); @@ -1516,7 +1527,10 @@ impl LinkCollector<'_, '_> { // Shouldn't happen but who knows? Ok((res, Some(fragment))) } - (fragment, None) | (None, fragment) => Ok((res, fragment)), + (fragment, None) => Ok((res, fragment)), + (None, fragment) => { + Ok((res, fragment.map(UrlFragment::UserWritten))) + } } } } @@ -1553,7 +1567,7 @@ impl LinkCollector<'_, '_> { } Some(MacroNS) => { match self.resolve_macro(path_str, base_node) { - Ok(res) => Some((res, extra_fragment.clone())), + Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))), Err(mut kind) => { // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible. for ns in [TypeNS, ValueNS] { @@ -2272,20 +2286,13 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: fn handle_variant( cx: &DocContext<'_>, res: Res, - extra_fragment: &Option, -) -> Result<(Res, Option), ErrorKind<'static>> { - use rustc_middle::ty::DefIdTree; - - if extra_fragment.is_some() { - // NOTE: `res` can never be a primitive since this function is only called when `tcx.def_kind(res) == DefKind::Variant`. - return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); - } +) -> Result<(Res, Option), ErrorKind<'static>> { cx.tcx .parent(res.def_id(cx.tcx)) .map(|parent| { let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap()); - (parent_def, Some(UrlFragment::Variant(variant.ident.name))) + (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id))) }) .ok_or_else(|| ResolutionFailure::NoParentItem.into()) }