Auto merge of #92690 - matthiaskrgr:rollup-rw0oz05, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #92055 (Add release notes for 1.58)
 - #92490 (Move crate drop-down to search results page)
 - #92510 (Don't resolve blocks in foreign functions)
 - #92573 (expand: Refactor InvocationCollector visitor for better code reuse)
 - #92608 (rustdoc: Introduce a resolver cache for sharing data between early doc link resolution and later passes)
 - #92657 (Implemented const casts of raw pointers)
 - #92671 (Make `Atomic*::from_mut` return `&mut Atomic*`)
 - #92673 (Remove useless collapse toggle on "all items" page)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-01-09 12:43:37 +00:00
commit f7bb8e3677
31 changed files with 1367 additions and 884 deletions

View File

@ -1,3 +1,169 @@
Version 1.58.0 (2022-01-13)
==========================
Language
--------
- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] This works in all macros accepting format strings. Support for this in `panic!` (`panic!("{ident}")`) requires the 2021 edition; panic invocations in previous editions that appear to be trying to use this will result in a warning lint about not having the intended effect.
- [`*const T` pointers can now be dereferenced in const contexts.][89551]
- [The rules for when a generic struct implements `Unsize` have been relaxed.][90417]
Compiler
--------
- [Add LLVM CFI support to the Rust compiler][89652]
- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. Note that this release only includes support in rustc, not directly in cargo.
- [Add support for LLVM coverage mapping format versions 5 and 6][91207]
- [Emit LLVM optimization remarks when enabled with `-Cremark`][90833]
- [Update the minimum external LLVM to 12][90175]
- [Add `x86_64-unknown-none` at Tier 3*][89062]
- [Build musl dist artifacts with debuginfo enabled][90733]. When building release binaries using musl, you may want to use the newly stabilized strip option to remove these debug symbols, reducing the size of your binaries.
- [Don't abort compilation after giving a lint error][87337]
- [Error messages point at the source of trait bound obligations in more places][89580]
\* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support.
Libraries
---------
- [All remaining functions in the standard library have `#[must_use]` annotations where appropriate][89692], producing a warning when ignoring their return value. This helps catch mistakes such as expecting a function to mutate a value in place rather than return a new value.
- [Paths are automatically canonicalized on Windows for operations that support it][89174]
- [Re-enable debug checks for `copy` and `copy_nonoverlapping`][90041]
- [Implement `RefUnwindSafe` for `Rc<T>`][87467]
- [Make RSplit<T, P>: Clone not require T: Clone][90117]
- [Implement `Termination` for `Result<Infallible, E>`][88601]. This allows writing `fn main() -> Result<Infallible, ErrorType>`, for a program whose successful exits never involve returning from `main` (for instance, a program that calls `exit`, or that uses `exec` to run another program).
Stabilized APIs
---------------
- [`Metadata::is_symlink`]
- [`Path::is_symlink`]
- [`{integer}::saturating_div`]
- [`Option::unwrap_unchecked`]
- [`NonZero{unsigned}::is_power_of_two`]
These APIs are now usable in const contexts:
- [`Duration::new`]
- [`Duration::checked_add`]
- [`Duration::saturating_add`]
- [`Duration::checked_sub`]
- [`Duration::saturating_sub`]
- [`Duration::checked_mul`]
- [`Duration::saturating_mul`]
- [`Duration::checked_div`]
- [`MaybeUninit::as_ptr`]
- [`MaybeUninit::as_mut_ptr`]
- [`MaybeUninit::assume_init`]
- [`MaybeUninit::assume_init_ref`]
Cargo
-----
- [Add --message-format for install command][cargo/10107]
- [Warn when alias shadows external subcommand][cargo/10082]
Rustdoc
-------
- [Show all Deref implementations recursively in rustdoc][90183]
- [Use computed visibility in rustdoc][88447]
Compatibility Notes
-------------------
- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library.
- Windows: [`std::process::Command` will no longer search the current directory for executables.][87704]
- [All proc-macro backward-compatibility lints are now deny-by-default.][88041]
- [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297]
- [Refactor weak symbols in std::sys::unix][90846]. This optimizes accesses to glibc functions, by avoiding the use of dlopen. This does not increase the [minimum expected version of glibc](https://doc.rust-lang.org/nightly/rustc/platform-support.html). However, software distributions that use symbol versions to detect library dependencies, and which take weak symbols into account in that analysis, may detect rust binaries as requiring newer versions of glibc.
- [rustdoc now rejects some unexpected semicolons in doctests][91026]
Internal Changes
----------------
These changes provide no direct user facing benefits, but represent significant
improvements to the internals and overall performance of rustc
and related tools.
- [Implement coherence checks for negative trait impls][90104]
- [Add rustc lint, warning when iterating over hashmaps][89558]
- [Optimize live point computation][90491]
- [Enable verification for 1/32nd of queries loaded from disk][90361]
- [Implement version of normalize_erasing_regions that allows for normalization failure][91255]
[87337]: https://github.com/rust-lang/rust/pull/87337/
[87467]: https://github.com/rust-lang/rust/pull/87467/
[87704]: https://github.com/rust-lang/rust/pull/87704/
[88041]: https://github.com/rust-lang/rust/pull/88041/
[88300]: https://github.com/rust-lang/rust/pull/88300/
[88447]: https://github.com/rust-lang/rust/pull/88447/
[88601]: https://github.com/rust-lang/rust/pull/88601/
[88624]: https://github.com/rust-lang/rust/pull/88624/
[89062]: https://github.com/rust-lang/rust/pull/89062/
[89174]: https://github.com/rust-lang/rust/pull/89174/
[89542]: https://github.com/rust-lang/rust/pull/89542/
[89551]: https://github.com/rust-lang/rust/pull/89551/
[89558]: https://github.com/rust-lang/rust/pull/89558/
[89580]: https://github.com/rust-lang/rust/pull/89580/
[89652]: https://github.com/rust-lang/rust/pull/89652/
[89677]: https://github.com/rust-lang/rust/pull/89677/
[89951]: https://github.com/rust-lang/rust/pull/89951/
[90041]: https://github.com/rust-lang/rust/pull/90041/
[90058]: https://github.com/rust-lang/rust/pull/90058/
[90104]: https://github.com/rust-lang/rust/pull/90104/
[90117]: https://github.com/rust-lang/rust/pull/90117/
[90175]: https://github.com/rust-lang/rust/pull/90175/
[90183]: https://github.com/rust-lang/rust/pull/90183/
[90297]: https://github.com/rust-lang/rust/pull/90297/
[90329]: https://github.com/rust-lang/rust/pull/90329/
[90361]: https://github.com/rust-lang/rust/pull/90361/
[90417]: https://github.com/rust-lang/rust/pull/90417/
[90473]: https://github.com/rust-lang/rust/pull/90473/
[90491]: https://github.com/rust-lang/rust/pull/90491/
[90733]: https://github.com/rust-lang/rust/pull/90733/
[90833]: https://github.com/rust-lang/rust/pull/90833/
[90846]: https://github.com/rust-lang/rust/pull/90846/
[90896]: https://github.com/rust-lang/rust/pull/90896/
[91026]: https://github.com/rust-lang/rust/pull/91026/
[91207]: https://github.com/rust-lang/rust/pull/91207/
[91255]: https://github.com/rust-lang/rust/pull/91255/
[91301]: https://github.com/rust-lang/rust/pull/91301/
[cargo/10082]: https://github.com/rust-lang/cargo/pull/10082/
[cargo/10107]: https://github.com/rust-lang/cargo/pull/10107/
[`Metadata::is_symlink`]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html#method.is_symlink
[`Path::is_symlink`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.is_symlink
[`{integer}::saturating_div`]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.saturating_div
[`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked
[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two
[`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped
[`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal
[`unix::process::ExitStatusExt::continued`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.continued
[`unix::process::ExitStatusExt::into_raw`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.into_raw
[`Duration::new`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.new
[`Duration::checked_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_add
[`Duration::saturating_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add
[`Duration::checked_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_sub
[`Duration::saturating_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_sub
[`Duration::checked_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_mul
[`Duration::saturating_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_mul
[`Duration::checked_div`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_div
[`Duration::as_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f64
[`Duration::as_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f32
[`Duration::from_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f64
[`Duration::from_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f32
[`Duration::mul_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f64
[`Duration::mul_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f32
[`Duration::div_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f64
[`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32
[`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64
[`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32
[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr
[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr
[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init
[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
Version 1.57.0 (2021-12-02) Version 1.57.0 (2021-12-02)
========================== ==========================
@ -388,6 +554,10 @@ Compatibility Notes
`Command` would cause them to be ASCII-uppercased. `Command` would cause them to be ASCII-uppercased.
- [Rustdoc will now warn on using rustdoc lints that aren't prefixed - [Rustdoc will now warn on using rustdoc lints that aren't prefixed
with `rustdoc::`][86849] with `rustdoc::`][86849]
- `RUSTFLAGS` is no longer set for build scripts. Build scripts
should use `CARGO_ENCODED_RUSTFLAGS` instead. See the
[documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)
for more details.
[86849]: https://github.com/rust-lang/rust/pull/86849 [86849]: https://github.com/rust-lang/rust/pull/86849
[86513]: https://github.com/rust-lang/rust/pull/86513 [86513]: https://github.com/rust-lang/rust/pull/86513

View File

@ -6,12 +6,13 @@ use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use super::{AttrVec, Attribute, Stmt, StmtKind}; use super::{AttrVec, Attribute, Stmt, StmtKind};
use std::fmt::Debug; use std::fmt;
use std::marker::PhantomData;
/// An `AstLike` represents an AST node (or some wrapper around /// An `AstLike` represents an AST node (or some wrapper around
/// and AST node) which stores some combination of attributes /// and AST node) which stores some combination of attributes
/// and tokens. /// and tokens.
pub trait AstLike: Sized + Debug { pub trait AstLike: Sized + fmt::Debug {
/// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
/// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
/// considered 'custom' attributes /// considered 'custom' attributes
@ -285,3 +286,37 @@ derive_has_attrs_no_tokens! {
derive_has_tokens_no_attrs! { derive_has_tokens_no_attrs! {
Ty, Block, AttrItem, Pat, Path, Visibility Ty, Block, AttrItem, Pat, Path, Visibility
} }
/// A newtype around an `AstLike` node that implements `AstLike` itself.
pub struct AstLikeWrapper<Wrapped, Tag> {
pub wrapped: Wrapped,
pub tag: PhantomData<Tag>,
}
impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
AstLikeWrapper { wrapped, tag: Default::default() }
}
}
impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AstLikeWrapper")
.field("wrapped", &self.wrapped)
.field("tag", &self.tag)
.finish()
}
}
impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS;
fn attrs(&self) -> &[Attribute] {
self.wrapped.attrs()
}
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
self.wrapped.visit_attrs(f)
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
self.wrapped.tokens_mut()
}
}

View File

@ -41,7 +41,7 @@ pub mod tokenstream;
pub mod visit; pub mod visit;
pub use self::ast::*; pub use self::ast::*;
pub use self::ast_like::AstLike; pub use self::ast_like::{AstLike, AstLikeWrapper};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

View File

@ -238,7 +238,7 @@ macro_rules! configure {
} }
impl<'a> StripUnconfigured<'a> { impl<'a> StripUnconfigured<'a> {
pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> { pub fn configure<T: AstLike>(&self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node); self.process_cfg_attrs(&mut node);
if self.in_cfg(node.attrs()) { if self.in_cfg(node.attrs()) {
self.try_configure_tokens(&mut node); self.try_configure_tokens(&mut node);
@ -248,7 +248,7 @@ impl<'a> StripUnconfigured<'a> {
} }
} }
fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) { fn try_configure_tokens<T: AstLike>(&self, node: &mut T) {
if self.config_tokens { if self.config_tokens {
if let Some(Some(tokens)) = node.tokens_mut() { if let Some(Some(tokens)) = node.tokens_mut() {
let attr_annotated_tokens = tokens.create_token_stream(); let attr_annotated_tokens = tokens.create_token_stream();
@ -257,10 +257,7 @@ impl<'a> StripUnconfigured<'a> {
} }
} }
fn configure_krate_attrs( fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
&mut self,
mut attrs: Vec<ast::Attribute>,
) -> Option<Vec<ast::Attribute>> {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
if self.in_cfg(&attrs) { Some(attrs) } else { None } if self.in_cfg(&attrs) { Some(attrs) } else { None }
} }
@ -269,7 +266,7 @@ impl<'a> StripUnconfigured<'a> {
/// This is only used during the invocation of `derive` proc-macros, /// This is only used during the invocation of `derive` proc-macros,
/// which require that we cfg-expand their entire input. /// which require that we cfg-expand their entire input.
/// Normal cfg-expansion operates on parsed AST nodes via the `configure` method /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool { fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
stream.0.iter().all(|(tree, _spacing)| match tree { stream.0.iter().all(|(tree, _spacing)| match tree {
AttrAnnotatedTokenTree::Attributes(_) => false, AttrAnnotatedTokenTree::Attributes(_) => false,
@ -325,7 +322,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives compiler warnings if any `cfg_attr` does not contain any /// Gives compiler warnings if any `cfg_attr` does not contain any
/// attributes and is in the original source code. Gives compiler errors if /// attributes and is in the original source code. Gives compiler errors if
/// the syntax of any `cfg_attr` is incorrect. /// the syntax of any `cfg_attr` is incorrect.
fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) { fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) {
node.visit_attrs(|attrs| { node.visit_attrs(|attrs| {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
}); });
@ -338,7 +335,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives a compiler warning when the `cfg_attr` contains no attributes and /// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of /// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect. /// the attribute is incorrect.
fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> { fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
if !attr.has_name(sym::cfg_attr) { if !attr.has_name(sym::cfg_attr) {
return vec![attr]; return vec![attr];
} }
@ -461,7 +458,7 @@ impl<'a> StripUnconfigured<'a> {
} }
} }
pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) { pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
for attr in expr.attrs.iter() { for attr in expr.attrs.iter() {
self.maybe_emit_expr_attr_err(attr); self.maybe_emit_expr_attr_err(attr);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
#![feature(associated_type_bounds)]
#![feature(associated_type_defaults)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(decl_macro)] #![feature(decl_macro)]
#![cfg_attr(bootstrap, feature(destructuring_assignment))] #![cfg_attr(bootstrap, feature(destructuring_assignment))]

View File

@ -123,7 +123,7 @@ pub fn placeholder(
span, span,
is_placeholder: true, is_placeholder: true,
}]), }]),
AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField { AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
attrs: Default::default(), attrs: Default::default(),
expr: expr_placeholder(), expr: expr_placeholder(),
id, id,
@ -132,7 +132,7 @@ pub fn placeholder(
span, span,
is_placeholder: true, is_placeholder: true,
}]), }]),
AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField { AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
attrs: Default::default(), attrs: Default::default(),
id, id,
ident, ident,
@ -159,7 +159,7 @@ pub fn placeholder(
ty: ty(), ty: ty(),
is_placeholder: true, is_placeholder: true,
}]), }]),
AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef { AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
attrs: Default::default(), attrs: Default::default(),
id, id,
ident: None, ident: None,

View File

@ -10,6 +10,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::metadata::ModChild; use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule}; use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
@ -187,8 +188,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
extra_filename => { cdata.root.extra_filename.clone() } extra_filename => { cdata.root.extra_filename.clone() }
traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } 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_of_trait(tcx, other) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
visibility => { cdata.get_visibility(def_id.index) } visibility => { cdata.get_visibility(def_id.index) }
@ -473,6 +472,17 @@ impl CStore {
) -> Span { ) -> Span {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
} }
pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec<DefId> {
self.get_crate_data(cnum).get_traits().collect()
}
pub fn trait_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> Vec<(DefId, Option<SimplifiedType>)> {
self.get_crate_data(cnum).get_trait_impls().collect()
}
} }
impl CrateStore for CStore { impl CrateStore for CStore {

View File

@ -1442,13 +1442,6 @@ rustc_queries! {
separate_provide_extern 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<SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
separate_provide_extern
}
query is_dllimport_foreign_item(def_id: DefId) -> bool { query is_dllimport_foreign_item(def_id: DefId) -> bool {
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
} }

View File

@ -520,9 +520,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
} }
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) { fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
let rib_kind = match fn_kind { let rib_kind = match fn_kind {
// Bail if there's no body. // Bail if the function is foreign, and thus cannot validly have
FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp), // a body, or if there's no body for some other reason.
FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind, FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
// We don't need to deal with patterns in parameters, because
// they are not possible for foreign or bodiless functions.
self.visit_fn_header(&sig.header);
visit::walk_fn_decl(self, &sig.decl);
return;
}
FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
FnKind::Closure(..) => ClosureOrAsyncRibKind, FnKind::Closure(..) => ClosureOrAsyncRibKind,
}; };

View File

@ -48,6 +48,16 @@ impl<T: ?Sized> *const T {
self as _ self as _
} }
/// Changes constness without changing the type.
///
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
/// refactored.
#[unstable(feature = "ptr_const_cast", issue = "92675")]
#[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
pub const fn as_mut(self) -> *mut T {
self as _
}
/// Casts a pointer to its raw bits. /// Casts a pointer to its raw bits.
/// ///
/// This is equivalent to `as usize`, but is more specific to enhance readability. /// This is equivalent to `as usize`, but is more specific to enhance readability.

View File

@ -47,6 +47,20 @@ impl<T: ?Sized> *mut T {
self as _ self as _
} }
/// Changes constness without changing the type.
///
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
/// refactored.
///
/// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry
/// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit
/// coercion.
#[unstable(feature = "ptr_const_cast", issue = "92675")]
#[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
pub const fn as_const(self) -> *const T {
self as _
}
/// Casts a pointer to its raw bits. /// Casts a pointer to its raw bits.
/// ///
/// This is equivalent to `as usize`, but is more specific to enhance readability. /// This is equivalent to `as usize`, but is more specific to enhance readability.

View File

@ -333,10 +333,10 @@ impl AtomicBool {
#[inline] #[inline]
#[cfg(target_has_atomic_equal_alignment = "8")] #[cfg(target_has_atomic_equal_alignment = "8")]
#[unstable(feature = "atomic_from_mut", issue = "76314")] #[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn from_mut(v: &mut bool) -> &Self { pub fn from_mut(v: &mut bool) -> &mut Self {
// SAFETY: the mutable reference guarantees unique ownership, and // SAFETY: the mutable reference guarantees unique ownership, and
// alignment of both `bool` and `Self` is 1. // alignment of both `bool` and `Self` is 1.
unsafe { &*(v as *mut bool as *mut Self) } unsafe { &mut *(v as *mut bool as *mut Self) }
} }
/// Consumes the atomic and returns the contained value. /// Consumes the atomic and returns the contained value.
@ -934,14 +934,14 @@ impl<T> AtomicPtr<T> {
#[inline] #[inline]
#[cfg(target_has_atomic_equal_alignment = "ptr")] #[cfg(target_has_atomic_equal_alignment = "ptr")]
#[unstable(feature = "atomic_from_mut", issue = "76314")] #[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn from_mut(v: &mut *mut T) -> &Self { pub fn from_mut(v: &mut *mut T) -> &mut Self {
use crate::mem::align_of; use crate::mem::align_of;
let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()]; let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
// SAFETY: // SAFETY:
// - the mutable reference guarantees unique ownership. // - the mutable reference guarantees unique ownership.
// - the alignment of `*mut T` and `Self` is the same on all platforms // - the alignment of `*mut T` and `Self` is the same on all platforms
// supported by rust, as verified above. // supported by rust, as verified above.
unsafe { &*(v as *mut *mut T as *mut Self) } unsafe { &mut *(v as *mut *mut T as *mut Self) }
} }
/// Consumes the atomic and returns the contained value. /// Consumes the atomic and returns the contained value.
@ -1447,14 +1447,14 @@ macro_rules! atomic_int {
#[inline] #[inline]
#[$cfg_align] #[$cfg_align]
#[unstable(feature = "atomic_from_mut", issue = "76314")] #[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn from_mut(v: &mut $int_type) -> &Self { pub fn from_mut(v: &mut $int_type) -> &mut Self {
use crate::mem::align_of; use crate::mem::align_of;
let [] = [(); align_of::<Self>() - align_of::<$int_type>()]; let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
// SAFETY: // SAFETY:
// - the mutable reference guarantees unique ownership. // - the mutable reference guarantees unique ownership.
// - the alignment of `$int_type` and `Self` is the // - the alignment of `$int_type` and `Self` is the
// same, as promised by $cfg_align and verified above. // same, as promised by $cfg_align and verified above.
unsafe { &*(v as *mut $int_type as *mut Self) } unsafe { &mut *(v as *mut $int_type as *mut Self) }
} }
/// Consumes the atomic and returns the contained value. /// Consumes the atomic and returns the contained value.

View File

@ -17,12 +17,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
pkg-config \ pkg-config \
mingw-w64 mingw-w64
RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
# Install es-check # Install es-check
# Pin its version to prevent unrelated CI failures due to future es-check versions. # Pin its version to prevent unrelated CI failures due to future es-check versions.
RUN npm install es-check@5.2.3 -g RUN npm install es-check@6.1.1 -g
RUN npm install eslint@7.20.0 -g RUN npm install eslint@8.6.0 -g
COPY scripts/sccache.sh /scripts/ COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh RUN sh /scripts/sccache.sh
@ -40,5 +40,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
/scripts/validate-toolstate.sh && \ /scripts/validate-toolstate.sh && \
/scripts/validate-error-codes.sh && \ /scripts/validate-error-codes.sh && \
# Runs checks to ensure that there are no ES5 issues in our JS code. # Runs checks to ensure that there are no ES5 issues in our JS code.
es-check es5 ../src/librustdoc/html/static/js/*.js && \ es-check es6 ../src/librustdoc/html/static/js/*.js && \
eslint ../src/librustdoc/html/static/js/*.js eslint ../src/librustdoc/html/static/js/*.js

View File

@ -19,23 +19,24 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
trace!("get_blanket_impls({:?})", ty); trace!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new(); let mut impls = Vec::new();
for trait_def_id in self.cx.tcx.all_traits() { self.cx.with_all_traits(|cx, all_traits| {
if !self.cx.cache.access_levels.is_public(trait_def_id) for &trait_def_id in all_traits {
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() if !cx.cache.access_levels.is_public(trait_def_id)
|| cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
{ {
continue; continue;
} }
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id); let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
for &impl_def_id in trait_impls.blanket_impls() { for &impl_def_id in trait_impls.blanket_impls() {
trace!( trace!(
"get_blanket_impls: Considering impl for trait '{:?}' {:?}", "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
trait_def_id, trait_def_id,
impl_def_id impl_def_id
); );
let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| { let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
let ty = ty.subst(infcx.tcx, substs); let ty = ty.subst(infcx.tcx, substs);
let param_env = param_env.subst(infcx.tcx, substs); let param_env = param_env.subst(infcx.tcx, substs);
@ -57,11 +58,10 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
trait_ref, trait_ref,
ty ty
); );
let predicates = self let predicates = cx
.cx
.tcx .tcx
.predicates_of(impl_def_id) .predicates_of(impl_def_id)
.instantiate(self.cx.tcx, impl_substs) .instantiate(cx.tcx, impl_substs)
.predicates .predicates
.into_iter() .into_iter()
.chain(Some( .chain(Some(
@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
continue; continue;
} }
self.cx.generated_synthetics.insert((ty, trait_def_id)); cx.generated_synthetics.insert((ty, trait_def_id));
impls.push(Item { impls.push(Item {
name: None, name: None,
@ -109,28 +109,29 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
kind: box ImplItem(Impl { kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal, unsafety: hir::Unsafety::Normal,
generics: clean_ty_generics( generics: clean_ty_generics(
self.cx, cx,
self.cx.tcx.generics_of(impl_def_id), cx.tcx.generics_of(impl_def_id),
self.cx.tcx.explicit_predicates_of(impl_def_id), cx.tcx.explicit_predicates_of(impl_def_id),
), ),
// FIXME(eddyb) compute both `trait_` and `for_` from // FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate. // the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx)), trait_: Some(trait_ref.clean(cx)),
for_: ty.clean(self.cx), for_: ty.clean(cx),
items: self items: cx
.cx
.tcx .tcx
.associated_items(impl_def_id) .associated_items(impl_def_id)
.in_definition_order() .in_definition_order()
.map(|x| x.clean(self.cx)) .map(|x| x.clean(cx))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive, polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)), kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
}), }),
cfg: None, cfg: None,
}); });
} }
} }
});
impls impls
} }
} }

View File

@ -291,6 +291,7 @@ crate fn build_impls(
attrs: Option<Attrs<'_>>, attrs: Option<Attrs<'_>>,
ret: &mut Vec<clean::Item>, ret: &mut Vec<clean::Item>,
) { ) {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
let tcx = cx.tcx; let tcx = cx.tcx;
// for each implementation of an item represented by `did`, build the clean::Item for that impl // for each implementation of an item represented by `did`, build the clean::Item for that impl
@ -338,7 +339,7 @@ crate fn build_impl(
return; return;
} }
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl"); let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
let tcx = cx.tcx; let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did); let associated_trait = tcx.impl_trait_ref(did);

View File

@ -179,6 +179,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
}; };
if let Some(prim) = target.primitive_type() { if let Some(prim) = target.primitive_type() {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) { for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
inline::build_impl(cx, None, did, None, ret); inline::build_impl(cx, None, did, None, ret);
} }

View File

@ -1,30 +1,23 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::sync::{self, Lrc};
use rustc_driver::abort_on_err;
use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter; use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures; use rustc_feature::UnstableFeatures;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::HirId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{ use rustc_hir::{HirId, Path};
intravisit::{self, NestedVisitorMap, Visitor}, use rustc_interface::interface;
Path,
};
use rustc_interface::{interface, Queries};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_resolve as resolve; use rustc_resolve as resolve;
use rustc_resolve::Namespace::TypeNS;
use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::config::{self, CrateType, ErrorOutputType};
use rustc_session::lint; use rustc_session::lint;
use rustc_session::DiagnosticOutput; use rustc_session::DiagnosticOutput;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::source_map;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{source_map, Span};
use std::cell::RefCell; use std::cell::RefCell;
use std::lazy::SyncLazy; use std::lazy::SyncLazy;
@ -39,14 +32,20 @@ use crate::passes::{self, Condition::*};
crate use rustc_session::config::{DebuggingOptions, Input, Options}; crate use rustc_session::config::{DebuggingOptions, Input, Options};
crate struct ResolverCaches {
pub all_traits: Option<Vec<DefId>>,
pub all_trait_impls: Option<Vec<DefId>>,
}
crate struct DocContext<'tcx> { crate struct DocContext<'tcx> {
crate tcx: TyCtxt<'tcx>, crate tcx: TyCtxt<'tcx>,
/// Name resolver. Used for intra-doc links. /// Name resolver. Used for intra-doc links.
/// ///
/// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by /// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by
/// [`Queries::expansion()`]. /// [`rustc_interface::Queries::expansion()`].
// FIXME: see if we can get rid of this RefCell somehow // FIXME: see if we can get rid of this RefCell somehow
crate resolver: Rc<RefCell<interface::BoxedResolver>>, crate resolver: Rc<RefCell<interface::BoxedResolver>>,
crate resolver_caches: ResolverCaches,
/// Used for normalization. /// Used for normalization.
/// ///
/// Most of this logic is copied from rustc_lint::late. /// Most of this logic is copied from rustc_lint::late.
@ -123,6 +122,18 @@ impl<'tcx> DocContext<'tcx> {
_ => None, _ => None,
} }
} }
crate fn with_all_traits(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
let all_traits = self.resolver_caches.all_traits.take();
f(self, all_traits.as_ref().expect("`all_traits` are already borrowed"));
self.resolver_caches.all_traits = all_traits;
}
crate fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
let all_trait_impls = self.resolver_caches.all_trait_impls.take();
f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed"));
self.resolver_caches.all_trait_impls = all_trait_impls;
}
} }
/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
@ -284,49 +295,10 @@ crate fn create_config(
} }
} }
crate fn create_resolver<'a>(
externs: config::Externs,
queries: &Queries<'a>,
sess: &Session,
) -> Rc<RefCell<interface::BoxedResolver>> {
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
let resolver = resolver.clone();
let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate);
// FIXME: somehow rustdoc is still missing crates even though we loaded all
// the known necessary crates. Load them all unconditionally until we find a way to fix this.
// DO NOT REMOVE THIS without first testing on the reproducer in
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
let extern_names: Vec<String> = externs
.iter()
.filter(|(_, entry)| entry.add_prelude)
.map(|(name, _)| name)
.cloned()
.collect();
resolver.borrow_mut().access(|resolver| {
sess.time("load_extern_crates", || {
for extern_name in &extern_names {
debug!("loading extern crate {}", extern_name);
if let Err(()) = resolver
.resolve_str_path_error(
DUMMY_SP,
extern_name,
TypeNS,
LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
) {
warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
}
}
});
});
resolver
}
crate fn run_global_ctxt( crate fn run_global_ctxt(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
resolver: Rc<RefCell<interface::BoxedResolver>>, resolver: Rc<RefCell<interface::BoxedResolver>>,
resolver_caches: ResolverCaches,
show_coverage: bool, show_coverage: bool,
render_options: RenderOptions, render_options: RenderOptions,
output_format: OutputFormat, output_format: OutputFormat,
@ -355,6 +327,14 @@ crate fn run_global_ctxt(
}); });
rustc_passes::stability::check_unused_or_stable_features(tcx); rustc_passes::stability::check_unused_or_stable_features(tcx);
let auto_traits = resolver_caches
.all_traits
.as_ref()
.expect("`all_traits` are already borrowed")
.iter()
.copied()
.filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
.collect();
let access_levels = AccessLevels { let access_levels = AccessLevels {
map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(), map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
}; };
@ -362,16 +342,14 @@ crate fn run_global_ctxt(
let mut ctxt = DocContext { let mut ctxt = DocContext {
tcx, tcx,
resolver, resolver,
resolver_caches,
param_env: ParamEnv::empty(), param_env: ParamEnv::empty(),
external_traits: Default::default(), external_traits: Default::default(),
active_extern_traits: Default::default(), active_extern_traits: Default::default(),
substs: Default::default(), substs: Default::default(),
impl_trait_bounds: Default::default(), impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(), generated_synthetics: Default::default(),
auto_traits: tcx auto_traits,
.all_traits()
.filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
.collect(),
module_trait_cache: FxHashMap::default(), module_trait_cache: FxHashMap::default(),
cache: Cache::new(access_levels, render_options.document_private), cache: Cache::new(access_levels, render_options.document_private),
inlined: FxHashSet::default(), inlined: FxHashSet::default(),

View File

@ -312,14 +312,6 @@ impl AllTypes {
f.write_str( f.write_str(
"<h1 class=\"fqn\">\ "<h1 class=\"fqn\">\
<span class=\"in-band\">List of all items</span>\ <span class=\"in-band\">List of all items</span>\
<span class=\"out-of-band\">\
<span id=\"render-detail\">\
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
title=\"collapse all docs\">\
[<span class=\"inner\">&#x2212;</span>]\
</a>\
</span>
</span>
</h1>", </h1>",
); );
// Note: print_entries does not escape the title, because we know the current set of titles // Note: print_entries does not escape the title, because we know the current set of titles

View File

@ -866,18 +866,24 @@ h2.small-section-header > .anchor {
display: inline-flex; display: inline-flex;
width: calc(100% - 63px); width: calc(100% - 63px);
} }
.search-results-title {
display: inline;
}
#search-settings {
font-size: 1.5rem;
font-weight: 500;
margin-bottom: 20px;
}
#crate-search { #crate-search {
min-width: 115px; min-width: 115px;
margin-top: 5px; margin-top: 5px;
padding: 6px; margin-left: 0.2em;
padding-right: 19px; padding-left: 0.3em;
flex: none; padding-right: 23px;
border: 0; border: 0;
border-right: 0; border-radius: 4px;
border-radius: 4px 0 0 4px;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
border-right: 1px solid;
-moz-appearance: none; -moz-appearance: none;
-webkit-appearance: none; -webkit-appearance: none;
/* Removes default arrow from firefox */ /* Removes default arrow from firefox */

View File

@ -1085,7 +1085,7 @@ window.initSearch = function(rawSearchIndex) {
return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>"; return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
} }
function showResults(results, go_to_first) { function showResults(results, go_to_first, filterCrates) {
var search = searchState.outputElement(); var search = searchState.outputElement();
if (go_to_first || (results.others.length === 1 if (go_to_first || (results.others.length === 1
&& getSettingValue("go-to-only-result") === "true" && getSettingValue("go-to-only-result") === "true"
@ -1126,9 +1126,16 @@ window.initSearch = function(rawSearchIndex) {
} }
} }
var output = "<h1>Results for " + escape(query.query) + let crates = `<select id="crate-search"><option value="All crates">All crates</option>`;
for (let c of window.ALL_CRATES) {
crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
}
crates += `</select>`;
var output = `<div id="search-settings">
<h1 class="search-results-title">Results for ${escape(query.query)} ` +
(query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" + (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
"<div id=\"titles\">" + ` in ${crates} ` +
`</div><div id="titles">` +
makeTabHeader(0, "In Names", ret_others[1]) + makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) + makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) + makeTabHeader(2, "In Return Types", ret_returned[1]) +
@ -1141,6 +1148,7 @@ window.initSearch = function(rawSearchIndex) {
resultsElem.appendChild(ret_returned[0]); resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output; search.innerHTML = output;
document.getElementById("crate-search").addEventListener("input", updateCrate);
search.appendChild(resultsElem); search.appendChild(resultsElem);
// Reset focused elements. // Reset focused elements.
searchState.focusedByTab = [null, null, null]; searchState.focusedByTab = [null, null, null];
@ -1316,7 +1324,8 @@ window.initSearch = function(rawSearchIndex) {
} }
var filterCrates = getFilterCrates(); var filterCrates = getFilterCrates();
showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]); showResults(execSearch(query, searchWords, filterCrates),
params["go_to_first"], filterCrates);
} }
function buildIndex(rawSearchIndex) { function buildIndex(rawSearchIndex) {
@ -1552,19 +1561,6 @@ window.initSearch = function(rawSearchIndex) {
} }
}); });
var selectCrate = document.getElementById("crate-search");
if (selectCrate) {
selectCrate.onchange = function() {
updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
// In case you "cut" the entry from the search input, then change the crate filter
// before paste back the previous search, you get the old search results without
// the filter. To prevent this, we need to remove the previous results.
currentResults = null;
search(undefined, true);
};
}
// Push and pop states are used to add search results to the browser // Push and pop states are used to add search results to the browser
// history. // history.
if (searchState.browserSupportsHistoryApi()) { if (searchState.browserSupportsHistoryApi()) {
@ -1616,6 +1612,15 @@ window.initSearch = function(rawSearchIndex) {
}; };
} }
function updateCrate(ev) {
updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value);
// In case you "cut" the entry from the search input, then change the crate filter
// before paste back the previous search, you get the old search results without
// the filter. To prevent this, we need to remove the previous results.
currentResults = null;
search(undefined, true);
}
searchWords = buildIndex(rawSearchIndex); searchWords = buildIndex(rawSearchIndex);
registerSearchEvents(); registerSearchEvents();
// If there's a search term in the URL, execute the search now. // If there's a search term in the URL, execute the search now.

View File

@ -105,11 +105,7 @@
</div> {#- -#} </div> {#- -#}
<form class="search-form"> {#- -#} <form class="search-form"> {#- -#}
<div class="search-container"> {#- -#} <div class="search-container"> {#- -#}
<div>{%- if layout.generate_search_filter -%} <div>
<select id="crate-search"> {#- -#}
<option value="All crates">All crates</option> {#- -#}
</select> {#- -#}
{%- endif -%}
<input {# -#} <input {# -#}
class="search-input" {# -#} class="search-input" {# -#}
name="search" {# -#} name="search" {# -#}

View File

@ -82,6 +82,7 @@ use rustc_session::getopts;
use rustc_session::{early_error, early_warn}; use rustc_session::{early_error, early_warn};
use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
use crate::passes::collect_intra_doc_links;
/// A macro to create a FxHashMap. /// A macro to create a FxHashMap.
/// ///
@ -798,7 +799,15 @@ fn main_options(options: config::Options) -> MainResult {
// We need to hold on to the complete resolver, so we cause everything to be // We need to hold on to the complete resolver, so we cause everything to be
// cloned for the analysis passes to use. Suboptimal, but necessary in the // cloned for the analysis passes to use. Suboptimal, but necessary in the
// current architecture. // current architecture.
let resolver = core::create_resolver(externs, queries, sess); // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
// two copies because one of the copies can be modified after `TyCtxt` construction.
let (resolver, resolver_caches) = {
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
let resolver_caches = resolver.borrow_mut().access(|resolver| {
collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate, externs)
});
(resolver.clone(), resolver_caches)
};
if sess.diagnostic().has_errors_or_lint_errors() { if sess.diagnostic().has_errors_or_lint_errors() {
sess.fatal("Compilation failed, aborting rustdoc"); sess.fatal("Compilation failed, aborting rustdoc");
@ -811,6 +820,7 @@ fn main_options(options: config::Options) -> MainResult {
core::run_global_ctxt( core::run_global_ctxt(
tcx, tcx,
resolver, resolver,
resolver_caches,
show_coverage, show_coverage,
render_options, render_options,
output_format, output_format,

View File

@ -38,7 +38,7 @@ use crate::passes::Pass;
use crate::visit::DocVisitor; use crate::visit::DocVisitor;
mod early; mod early;
crate use early::load_intra_link_crates; crate use early::early_resolve_intra_doc_links;
crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
name: "collect-intra-doc-links", name: "collect-intra-doc-links",

View File

@ -1,98 +1,136 @@
use ast::visit; use crate::clean;
use rustc_ast as ast; use crate::core::ResolverCaches;
use crate::html::markdown::markdown_links;
use crate::passes::collect_intra_doc_links::preprocess_link;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, ItemKind};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def::Namespace::TypeNS;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_interface::interface; use rustc_resolve::Resolver;
use rustc_span::Span; use rustc_session::config::Externs;
use rustc_span::{Span, DUMMY_SP};
use std::cell::RefCell;
use std::mem; use std::mem;
use std::rc::Rc;
type Resolver = Rc<RefCell<interface::BoxedResolver>>; crate fn early_resolve_intra_doc_links(
// Letting the resolver escape at the end of the function leads to inconsistencies between the resolver: &mut Resolver<'_>,
// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates krate: &ast::Crate,
// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ... externs: Externs,
crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver { ) -> ResolverCaches {
let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver }; let mut loader = IntraLinkCrateLoader {
// `walk_crate` doesn't visit the crate itself for some reason. resolver,
current_mod: CRATE_DEF_ID,
all_traits: Default::default(),
all_trait_impls: Default::default(),
};
// Overridden `visit_item` below doesn't apply to the crate root,
// so we have to visit its attributes and exports separately.
loader.load_links_in_attrs(&krate.attrs, krate.span); loader.load_links_in_attrs(&krate.attrs, krate.span);
visit::walk_crate(&mut loader, krate); visit::walk_crate(&mut loader, krate);
loader.resolver loader.fill_resolver_caches();
// FIXME: somehow rustdoc is still missing crates even though we loaded all
// the known necessary crates. Load them all unconditionally until we find a way to fix this.
// DO NOT REMOVE THIS without first testing on the reproducer in
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
let _ = loader.resolver.resolve_str_path_error(
DUMMY_SP,
extern_name,
TypeNS,
CRATE_DEF_ID.to_def_id(),
);
}
ResolverCaches {
all_traits: Some(loader.all_traits),
all_trait_impls: Some(loader.all_trait_impls),
}
} }
struct IntraLinkCrateLoader { struct IntraLinkCrateLoader<'r, 'ra> {
resolver: &'r mut Resolver<'ra>,
current_mod: LocalDefId, current_mod: LocalDefId,
resolver: Rc<RefCell<interface::BoxedResolver>>, all_traits: Vec<DefId>,
all_trait_impls: Vec<DefId>,
} }
impl IntraLinkCrateLoader { impl IntraLinkCrateLoader<'_, '_> {
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { fn fill_resolver_caches(&mut self) {
use crate::html::markdown::markdown_links; for cnum in self.resolver.cstore().crates_untracked() {
use crate::passes::collect_intra_doc_links::preprocess_link; let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum);
let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum);
// FIXME: this probably needs to consider inlining self.all_traits.extend(all_traits);
let attrs = crate::clean::Attributes::from_ast(attrs, None); self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id));
}
}
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
// FIXME: this needs to consider export inlining.
let attrs = clean::Attributes::from_ast(attrs, None);
for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() { for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
debug!(?doc); let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
for link in markdown_links(doc.as_str()) {
debug!(?link.link); for link in markdown_links(&doc.as_str()) {
let path_str = if let Some(Ok(x)) = preprocess_link(&link) { let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
x.path_str x.path_str
} else { } else {
continue; continue;
}; };
self.resolver.borrow_mut().access(|resolver| { let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
let _ = resolver.resolve_str_path_error(
span,
&path_str,
TypeNS,
parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
);
});
} }
} }
} }
} }
impl visit::Visitor<'_> for IntraLinkCrateLoader { impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_foreign_item(self, item)
}
fn visit_item(&mut self, item: &ast::Item) { fn visit_item(&mut self, item: &ast::Item) {
use rustc_ast_lowering::ResolverAstLowering; if let ItemKind::Mod(..) = item.kind {
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
if let ast::ItemKind::Mod(..) = item.kind {
let new_mod =
self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
let old_mod = mem::replace(&mut self.current_mod, new_mod);
self.load_links_in_attrs(&item.attrs, item.span); self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item); visit::walk_item(self, item);
self.current_mod = old_mod; self.current_mod = old_mod;
} else { } else {
match item.kind {
ItemKind::Trait(..) => {
self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
}
ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
}
_ => {}
}
self.load_links_in_attrs(&item.attrs, item.span); self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_item(self, item); visit::walk_item(self, item);
} }
} }
// NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too. fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
self.load_links_in_attrs(&item.attrs, item.span); self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_assoc_item(self, item, ctxt) visit::walk_assoc_item(self, item, ctxt)
} }
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
self.load_links_in_attrs(&item.attrs, item.span);
visit::walk_foreign_item(self, item)
}
fn visit_variant(&mut self, v: &ast::Variant) {
self.load_links_in_attrs(&v.attrs, v.span);
visit::walk_variant(self, v)
}
fn visit_field_def(&mut self, field: &ast::FieldDef) { fn visit_field_def(&mut self, field: &ast::FieldDef) {
self.load_links_in_attrs(&field.attrs, field.span); self.load_links_in_attrs(&field.attrs, field.span);
visit::walk_field_def(self, field) visit::walk_field_def(self, field)
} }
fn visit_variant(&mut self, v: &ast::Variant) { // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
self.load_links_in_attrs(&v.attrs, v.span); // then this will have to implement other visitor methods too.
visit::walk_variant(self, v)
}
} }

View File

@ -34,16 +34,18 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
let mut new_items = Vec::new(); let mut new_items = Vec::new();
for &cnum in cx.tcx.crates(()).iter() { // External trait impls.
for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() { cx.with_all_trait_impls(|cx, all_trait_impls| {
inline::build_impl(cx, None, did, None, &mut new_items); let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
} for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) {
inline::build_impl(cx, None, impl_def_id, None, &mut new_items);
} }
});
// Also try to inline primitive impls from other crates. // Also try to inline primitive impls from other crates.
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
if !def_id.is_local() { if !def_id.is_local() {
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
inline::build_impl(cx, None, def_id, None, &mut new_items); inline::build_impl(cx, None, def_id, None, &mut new_items);
// FIXME(eddyb) is this `doc(hidden)` check needed? // FIXME(eddyb) is this `doc(hidden)` check needed?
@ -51,9 +53,9 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
let impls = get_auto_trait_and_blanket_impls(cx, def_id); let impls = get_auto_trait_and_blanket_impls(cx, def_id);
new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id))); new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
} }
}
}
}); });
}
}
let mut cleaner = BadImplStripper { prims, items: crate_items }; let mut cleaner = BadImplStripper { prims, items: crate_items };
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default(); let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
@ -126,16 +128,14 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
} }
}); });
// `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations` // Local trait impls.
// doesn't work with it anyway, so pull them from the HIR map instead cx.with_all_trait_impls(|cx, all_trait_impls| {
let mut extra_attrs = Vec::new(); let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
for trait_did in cx.tcx.all_traits() { let mut attr_buf = Vec::new();
for &impl_did in cx.tcx.hir().trait_impls(trait_did) { for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
let impl_did = impl_did.to_def_id(); let mut parent = cx.tcx.parent(impl_def_id);
cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {
let mut parent = cx.tcx.parent(impl_did);
while let Some(did) = parent { while let Some(did) = parent {
extra_attrs.extend( attr_buf.extend(
cx.tcx cx.tcx
.get_attrs(did) .get_attrs(did)
.iter() .iter()
@ -151,11 +151,10 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
); );
parent = cx.tcx.parent(did); parent = cx.tcx.parent(did);
} }
inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items); inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
extra_attrs.clear(); attr_buf.clear();
}
}); });
}
}
if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind { if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
items.extend(synth_impls); items.extend(synth_impls);

View File

@ -1,7 +1,7 @@
goto: file://|DOC_PATH|/test_docs/index.html goto: file://|DOC_PATH|/test_docs/index.html
// First, we check that the search results are hidden when the Escape key is pressed. // First, we check that the search results are hidden when the Escape key is pressed.
write: (".search-input", "test") write: (".search-input", "test")
wait-for: "#search > h1" // The search element is empty before the first search wait-for: "#search h1" // The search element is empty before the first search
assert-attribute: ("#search", {"class": "content"}) assert-attribute: ("#search", {"class": "content"})
assert-attribute: ("#main-content", {"class": "content hidden"}) assert-attribute: ("#main-content", {"class": "content hidden"})
press-key: "Escape" press-key: "Escape"

View File

@ -5,14 +5,12 @@ write: (".search-input", "test")
wait-for: "#titles" wait-for: "#titles"
assert-text: ("#results .externcrate", "test_docs") assert-text: ("#results .externcrate", "test_docs")
goto: file://|DOC_PATH|/test_docs/index.html wait-for: "#crate-search"
// We now want to change the crate filter. // We now want to change the crate filter.
click: "#crate-search" click: "#crate-search"
// We select "lib2" option then press enter to change the filter. // We select "lib2" option then press enter to change the filter.
press-key: "ArrowDown" press-key: "ArrowDown"
press-key: "Enter" press-key: "Enter"
// We now make the search again.
write: (".search-input", "test")
// Waiting for the search results to appear... // Waiting for the search results to appear...
wait-for: "#titles" wait-for: "#titles"
// We check that there is no more "test_docs" appearing. // We check that there is no more "test_docs" appearing.

View File

@ -1,12 +1,12 @@
goto: file://|DOC_PATH|/test_docs/struct.Foo.html goto: file://|DOC_PATH|/test_docs/struct.Foo.html
size: (433, 600) size: (433, 600)
assert-attribute: (".top-doc", {"open": ""}) assert-attribute: (".top-doc", {"open": ""})
click: (4, 280) // This is the position of the top doc comment toggle click: (4, 240) // This is the position of the top doc comment toggle
assert-attribute-false: (".top-doc", {"open": ""}) assert-attribute-false: (".top-doc", {"open": ""})
click: (4, 280) click: (4, 240)
assert-attribute: (".top-doc", {"open": ""}) assert-attribute: (".top-doc", {"open": ""})
// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
click: (3, 280) click: (3, 240)
assert-attribute: (".top-doc", {"open": ""}) assert-attribute: (".top-doc", {"open": ""})
// Assert the position of the toggle on the top doc block. // Assert the position of the toggle on the top doc block.

View File

@ -0,0 +1,12 @@
// Regression test for issue #91370.
extern {
//~^ `extern` blocks define existing foreign functions
fn f() {
//~^ incorrect function inside `extern` block
//~| cannot have a body
impl Copy for u8 {}
}
}
fn main() {}

View File

@ -0,0 +1,21 @@
error: incorrect function inside `extern` block
--> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8
|
LL | extern {
| ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
LL |
LL | fn f() {
| ________^___-
| | |
| | cannot have a body
LL | |
LL | |
LL | | impl Copy for u8 {}
LL | | }
| |_____- help: remove the invalid body: `;`
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to previous error