mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
commit
f7bb8e3677
170
RELEASES.md
170
RELEASES.md
@ -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)
|
||||
==========================
|
||||
|
||||
@ -388,6 +554,10 @@ Compatibility Notes
|
||||
`Command` would cause them to be ASCII-uppercased.
|
||||
- [Rustdoc will now warn on using rustdoc lints that aren't prefixed
|
||||
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
|
||||
[86513]: https://github.com/rust-lang/rust/pull/86513
|
||||
|
@ -6,12 +6,13 @@ use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
|
||||
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
|
||||
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
|
||||
/// and AST node) which stores some combination of attributes
|
||||
/// 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
|
||||
/// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
|
||||
/// considered 'custom' attributes
|
||||
@ -285,3 +286,37 @@ derive_has_attrs_no_tokens! {
|
||||
derive_has_tokens_no_attrs! {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ pub mod tokenstream;
|
||||
pub mod visit;
|
||||
|
||||
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};
|
||||
|
||||
|
@ -238,7 +238,7 @@ macro_rules! configure {
|
||||
}
|
||||
|
||||
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);
|
||||
if self.in_cfg(node.attrs()) {
|
||||
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 let Some(Some(tokens)) = node.tokens_mut() {
|
||||
let attr_annotated_tokens = tokens.create_token_stream();
|
||||
@ -257,10 +257,7 @@ impl<'a> StripUnconfigured<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_krate_attrs(
|
||||
&mut self,
|
||||
mut attrs: Vec<ast::Attribute>,
|
||||
) -> Option<Vec<ast::Attribute>> {
|
||||
fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
|
||||
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
|
||||
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,
|
||||
/// which require that we cfg-expand their entire input.
|
||||
/// 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 {
|
||||
stream.0.iter().all(|(tree, _spacing)| match tree {
|
||||
AttrAnnotatedTokenTree::Attributes(_) => false,
|
||||
@ -325,7 +322,7 @@ impl<'a> StripUnconfigured<'a> {
|
||||
/// Gives compiler warnings if any `cfg_attr` does not contain any
|
||||
/// attributes and is in the original source code. Gives compiler errors if
|
||||
/// 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| {
|
||||
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
|
||||
/// is in the original source file. Gives a compiler error if the syntax of
|
||||
/// 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) {
|
||||
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() {
|
||||
self.maybe_emit_expr_attr_err(attr);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![cfg_attr(bootstrap, feature(destructuring_assignment))]
|
||||
|
@ -123,7 +123,7 @@ pub fn placeholder(
|
||||
span,
|
||||
is_placeholder: true,
|
||||
}]),
|
||||
AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField {
|
||||
AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
|
||||
attrs: Default::default(),
|
||||
expr: expr_placeholder(),
|
||||
id,
|
||||
@ -132,7 +132,7 @@ pub fn placeholder(
|
||||
span,
|
||||
is_placeholder: true,
|
||||
}]),
|
||||
AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
|
||||
AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
|
||||
attrs: Default::default(),
|
||||
id,
|
||||
ident,
|
||||
@ -159,7 +159,7 @@ pub fn placeholder(
|
||||
ty: ty(),
|
||||
is_placeholder: true,
|
||||
}]),
|
||||
AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef {
|
||||
AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
|
||||
attrs: Default::default(),
|
||||
id,
|
||||
ident: None,
|
||||
|
@ -10,6 +10,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
||||
use rustc_middle::metadata::ModChild;
|
||||
use rustc_middle::middle::exported_symbols::ExportedSymbol;
|
||||
use rustc_middle::middle::stability::DeprecationEntry;
|
||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_middle::ty::{self, TyCtxt, Visibility};
|
||||
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() }
|
||||
|
||||
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) }
|
||||
|
||||
visibility => { cdata.get_visibility(def_id.index) }
|
||||
@ -473,6 +472,17 @@ impl CStore {
|
||||
) -> Span {
|
||||
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 {
|
||||
|
@ -1442,13 +1442,6 @@ rustc_queries! {
|
||||
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 {
|
||||
desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
@ -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) {
|
||||
let rib_kind = match fn_kind {
|
||||
// Bail if there's no body.
|
||||
FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp),
|
||||
FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind,
|
||||
// Bail if the function is foreign, and thus cannot validly have
|
||||
// a body, or if there's no body for some other reason.
|
||||
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::Closure(..) => ClosureOrAsyncRibKind,
|
||||
};
|
||||
|
@ -48,6 +48,16 @@ impl<T: ?Sized> *const T {
|
||||
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.
|
||||
///
|
||||
/// This is equivalent to `as usize`, but is more specific to enhance readability.
|
||||
|
@ -47,6 +47,20 @@ impl<T: ?Sized> *mut T {
|
||||
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.
|
||||
///
|
||||
/// This is equivalent to `as usize`, but is more specific to enhance readability.
|
||||
|
@ -333,10 +333,10 @@ impl AtomicBool {
|
||||
#[inline]
|
||||
#[cfg(target_has_atomic_equal_alignment = "8")]
|
||||
#[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
|
||||
// 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.
|
||||
@ -934,14 +934,14 @@ impl<T> AtomicPtr<T> {
|
||||
#[inline]
|
||||
#[cfg(target_has_atomic_equal_alignment = "ptr")]
|
||||
#[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;
|
||||
let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
|
||||
// SAFETY:
|
||||
// - the mutable reference guarantees unique ownership.
|
||||
// - the alignment of `*mut T` and `Self` is the same on all platforms
|
||||
// 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.
|
||||
@ -1447,14 +1447,14 @@ macro_rules! atomic_int {
|
||||
#[inline]
|
||||
#[$cfg_align]
|
||||
#[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;
|
||||
let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
|
||||
// SAFETY:
|
||||
// - the mutable reference guarantees unique ownership.
|
||||
// - the alignment of `$int_type` and `Self` is the
|
||||
// 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.
|
||||
|
@ -17,12 +17,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config \
|
||||
mingw-w64
|
||||
|
||||
RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
|
||||
ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
|
||||
RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
|
||||
ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
|
||||
# Install es-check
|
||||
# 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 eslint@7.20.0 -g
|
||||
RUN npm install es-check@6.1.1 -g
|
||||
RUN npm install eslint@8.6.0 -g
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
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-error-codes.sh && \
|
||||
# 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
|
||||
|
@ -19,118 +19,119 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||
|
||||
trace!("get_blanket_impls({:?})", ty);
|
||||
let mut impls = Vec::new();
|
||||
for trait_def_id in self.cx.tcx.all_traits() {
|
||||
if !self.cx.cache.access_levels.is_public(trait_def_id)
|
||||
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// 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);
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
trace!(
|
||||
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
|
||||
trait_def_id,
|
||||
impl_def_id
|
||||
);
|
||||
let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
|
||||
let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
|
||||
let ty = ty.subst(infcx.tcx, substs);
|
||||
let param_env = param_env.subst(infcx.tcx, substs);
|
||||
|
||||
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
||||
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
|
||||
|
||||
// Require the type the impl is implemented on to match
|
||||
// our type, and ignore the impl if there was a mismatch.
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
|
||||
if let Ok(InferOk { value: (), obligations }) = eq_result {
|
||||
// FIXME(eddyb) ignoring `obligations` might cause false positives.
|
||||
drop(obligations);
|
||||
|
||||
trace!(
|
||||
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
|
||||
param_env,
|
||||
trait_ref,
|
||||
ty
|
||||
);
|
||||
let predicates = self
|
||||
.cx
|
||||
.tcx
|
||||
.predicates_of(impl_def_id)
|
||||
.instantiate(self.cx.tcx, impl_substs)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.chain(Some(
|
||||
ty::Binder::dummy(trait_ref)
|
||||
.to_poly_trait_predicate()
|
||||
.map_bound(ty::PredicateKind::Trait)
|
||||
.to_predicate(infcx.tcx),
|
||||
));
|
||||
for predicate in predicates {
|
||||
debug!("testing predicate {:?}", predicate);
|
||||
let obligation = traits::Obligation::new(
|
||||
traits::ObligationCause::dummy(),
|
||||
param_env,
|
||||
predicate,
|
||||
);
|
||||
match infcx.evaluate_obligation(&obligation) {
|
||||
Ok(eval_result) if eval_result.may_apply() => {}
|
||||
Err(traits::OverflowError::Canonical) => {}
|
||||
Err(traits::OverflowError::ErrorReporting) => {}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
debug!(
|
||||
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
|
||||
may_apply, trait_ref, ty
|
||||
);
|
||||
if !may_apply {
|
||||
self.cx.with_all_traits(|cx, all_traits| {
|
||||
for &trait_def_id in all_traits {
|
||||
if !cx.cache.access_levels.is_public(trait_def_id)
|
||||
|| cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
|
||||
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
trace!(
|
||||
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
|
||||
trait_def_id,
|
||||
impl_def_id
|
||||
);
|
||||
let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
|
||||
let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
|
||||
let ty = ty.subst(infcx.tcx, substs);
|
||||
let param_env = param_env.subst(infcx.tcx, substs);
|
||||
|
||||
self.cx.generated_synthetics.insert((ty, trait_def_id));
|
||||
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
||||
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
|
||||
|
||||
impls.push(Item {
|
||||
name: None,
|
||||
attrs: Default::default(),
|
||||
visibility: Inherited,
|
||||
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
|
||||
kind: box ImplItem(Impl {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
generics: clean_ty_generics(
|
||||
self.cx,
|
||||
self.cx.tcx.generics_of(impl_def_id),
|
||||
self.cx.tcx.explicit_predicates_of(impl_def_id),
|
||||
),
|
||||
// FIXME(eddyb) compute both `trait_` and `for_` from
|
||||
// the post-inference `trait_ref`, as it's more accurate.
|
||||
trait_: Some(trait_ref.clean(self.cx)),
|
||||
for_: ty.clean(self.cx),
|
||||
items: self
|
||||
.cx
|
||||
.tcx
|
||||
.associated_items(impl_def_id)
|
||||
.in_definition_order()
|
||||
.map(|x| x.clean(self.cx))
|
||||
.collect::<Vec<_>>(),
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
|
||||
}),
|
||||
cfg: None,
|
||||
});
|
||||
// Require the type the impl is implemented on to match
|
||||
// our type, and ignore the impl if there was a mismatch.
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
|
||||
if let Ok(InferOk { value: (), obligations }) = eq_result {
|
||||
// FIXME(eddyb) ignoring `obligations` might cause false positives.
|
||||
drop(obligations);
|
||||
|
||||
trace!(
|
||||
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
|
||||
param_env,
|
||||
trait_ref,
|
||||
ty
|
||||
);
|
||||
let predicates = cx
|
||||
.tcx
|
||||
.predicates_of(impl_def_id)
|
||||
.instantiate(cx.tcx, impl_substs)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.chain(Some(
|
||||
ty::Binder::dummy(trait_ref)
|
||||
.to_poly_trait_predicate()
|
||||
.map_bound(ty::PredicateKind::Trait)
|
||||
.to_predicate(infcx.tcx),
|
||||
));
|
||||
for predicate in predicates {
|
||||
debug!("testing predicate {:?}", predicate);
|
||||
let obligation = traits::Obligation::new(
|
||||
traits::ObligationCause::dummy(),
|
||||
param_env,
|
||||
predicate,
|
||||
);
|
||||
match infcx.evaluate_obligation(&obligation) {
|
||||
Ok(eval_result) if eval_result.may_apply() => {}
|
||||
Err(traits::OverflowError::Canonical) => {}
|
||||
Err(traits::OverflowError::ErrorReporting) => {}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
debug!(
|
||||
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
|
||||
may_apply, trait_ref, ty
|
||||
);
|
||||
if !may_apply {
|
||||
continue;
|
||||
}
|
||||
|
||||
cx.generated_synthetics.insert((ty, trait_def_id));
|
||||
|
||||
impls.push(Item {
|
||||
name: None,
|
||||
attrs: Default::default(),
|
||||
visibility: Inherited,
|
||||
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
|
||||
kind: box ImplItem(Impl {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
generics: clean_ty_generics(
|
||||
cx,
|
||||
cx.tcx.generics_of(impl_def_id),
|
||||
cx.tcx.explicit_predicates_of(impl_def_id),
|
||||
),
|
||||
// FIXME(eddyb) compute both `trait_` and `for_` from
|
||||
// the post-inference `trait_ref`, as it's more accurate.
|
||||
trait_: Some(trait_ref.clean(cx)),
|
||||
for_: ty.clean(cx),
|
||||
items: cx
|
||||
.tcx
|
||||
.associated_items(impl_def_id)
|
||||
.in_definition_order()
|
||||
.map(|x| x.clean(cx))
|
||||
.collect::<Vec<_>>(),
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
|
||||
}),
|
||||
cfg: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
impls
|
||||
}
|
||||
}
|
||||
|
@ -291,6 +291,7 @@ crate fn build_impls(
|
||||
attrs: Option<Attrs<'_>>,
|
||||
ret: &mut Vec<clean::Item>,
|
||||
) {
|
||||
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
|
||||
let tcx = cx.tcx;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 associated_trait = tcx.impl_trait_ref(did);
|
||||
|
@ -179,6 +179,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
|
||||
};
|
||||
|
||||
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()) {
|
||||
inline::build_impl(cx, None, did, None, ret);
|
||||
}
|
||||
|
@ -1,30 +1,23 @@
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_driver::abort_on_err;
|
||||
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::{
|
||||
intravisit::{self, NestedVisitorMap, Visitor},
|
||||
Path,
|
||||
};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{HirId, Path};
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::middle::privacy::AccessLevels;
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_resolve as resolve;
|
||||
use rustc_resolve::Namespace::TypeNS;
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::DiagnosticOutput;
|
||||
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::{Span, DUMMY_SP};
|
||||
use rustc_span::{source_map, Span};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::lazy::SyncLazy;
|
||||
@ -39,14 +32,20 @@ use crate::passes::{self, Condition::*};
|
||||
|
||||
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 tcx: TyCtxt<'tcx>,
|
||||
/// Name resolver. Used for intra-doc links.
|
||||
///
|
||||
/// 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
|
||||
crate resolver: Rc<RefCell<interface::BoxedResolver>>,
|
||||
crate resolver_caches: ResolverCaches,
|
||||
/// Used for normalization.
|
||||
///
|
||||
/// Most of this logic is copied from rustc_lint::late.
|
||||
@ -123,6 +122,18 @@ impl<'tcx> DocContext<'tcx> {
|
||||
_ => 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.
|
||||
@ -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(
|
||||
tcx: TyCtxt<'_>,
|
||||
resolver: Rc<RefCell<interface::BoxedResolver>>,
|
||||
resolver_caches: ResolverCaches,
|
||||
show_coverage: bool,
|
||||
render_options: RenderOptions,
|
||||
output_format: OutputFormat,
|
||||
@ -355,6 +327,14 @@ crate fn run_global_ctxt(
|
||||
});
|
||||
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 {
|
||||
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 {
|
||||
tcx,
|
||||
resolver,
|
||||
resolver_caches,
|
||||
param_env: ParamEnv::empty(),
|
||||
external_traits: Default::default(),
|
||||
active_extern_traits: Default::default(),
|
||||
substs: Default::default(),
|
||||
impl_trait_bounds: Default::default(),
|
||||
generated_synthetics: Default::default(),
|
||||
auto_traits: tcx
|
||||
.all_traits()
|
||||
.filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
|
||||
.collect(),
|
||||
auto_traits,
|
||||
module_trait_cache: FxHashMap::default(),
|
||||
cache: Cache::new(access_levels, render_options.document_private),
|
||||
inlined: FxHashSet::default(),
|
||||
|
@ -312,14 +312,6 @@ impl AllTypes {
|
||||
f.write_str(
|
||||
"<h1 class=\"fqn\">\
|
||||
<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\">−</span>]\
|
||||
</a>\
|
||||
</span>
|
||||
</span>
|
||||
</h1>",
|
||||
);
|
||||
// Note: print_entries does not escape the title, because we know the current set of titles
|
||||
|
@ -866,18 +866,24 @@ h2.small-section-header > .anchor {
|
||||
display: inline-flex;
|
||||
width: calc(100% - 63px);
|
||||
}
|
||||
.search-results-title {
|
||||
display: inline;
|
||||
}
|
||||
#search-settings {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#crate-search {
|
||||
min-width: 115px;
|
||||
margin-top: 5px;
|
||||
padding: 6px;
|
||||
padding-right: 19px;
|
||||
flex: none;
|
||||
margin-left: 0.2em;
|
||||
padding-left: 0.3em;
|
||||
padding-right: 23px;
|
||||
border: 0;
|
||||
border-right: 0;
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
/* Removes default arrow from firefox */
|
||||
|
@ -1085,7 +1085,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
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();
|
||||
if (go_to_first || (results.others.length === 1
|
||||
&& 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>" +
|
||||
"<div id=\"titles\">" +
|
||||
` in ${crates} ` +
|
||||
`</div><div id="titles">` +
|
||||
makeTabHeader(0, "In Names", ret_others[1]) +
|
||||
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
|
||||
makeTabHeader(2, "In Return Types", ret_returned[1]) +
|
||||
@ -1141,6 +1148,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
resultsElem.appendChild(ret_returned[0]);
|
||||
|
||||
search.innerHTML = output;
|
||||
document.getElementById("crate-search").addEventListener("input", updateCrate);
|
||||
search.appendChild(resultsElem);
|
||||
// Reset focused elements.
|
||||
searchState.focusedByTab = [null, null, null];
|
||||
@ -1316,7 +1324,8 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -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
|
||||
// history.
|
||||
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);
|
||||
registerSearchEvents();
|
||||
// If there's a search term in the URL, execute the search now.
|
||||
|
@ -105,11 +105,7 @@
|
||||
</div> {#- -#}
|
||||
<form class="search-form"> {#- -#}
|
||||
<div class="search-container"> {#- -#}
|
||||
<div>{%- if layout.generate_search_filter -%}
|
||||
<select id="crate-search"> {#- -#}
|
||||
<option value="All crates">All crates</option> {#- -#}
|
||||
</select> {#- -#}
|
||||
{%- endif -%}
|
||||
<div>
|
||||
<input {# -#}
|
||||
class="search-input" {# -#}
|
||||
name="search" {# -#}
|
||||
|
@ -82,6 +82,7 @@ use rustc_session::getopts;
|
||||
use rustc_session::{early_error, early_warn};
|
||||
|
||||
use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
|
||||
use crate::passes::collect_intra_doc_links;
|
||||
|
||||
/// 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
|
||||
// cloned for the analysis passes to use. Suboptimal, but necessary in the
|
||||
// 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() {
|
||||
sess.fatal("Compilation failed, aborting rustdoc");
|
||||
@ -811,6 +820,7 @@ fn main_options(options: config::Options) -> MainResult {
|
||||
core::run_global_ctxt(
|
||||
tcx,
|
||||
resolver,
|
||||
resolver_caches,
|
||||
show_coverage,
|
||||
render_options,
|
||||
output_format,
|
||||
|
@ -38,7 +38,7 @@ use crate::passes::Pass;
|
||||
use crate::visit::DocVisitor;
|
||||
|
||||
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 {
|
||||
name: "collect-intra-doc-links",
|
||||
|
@ -1,98 +1,136 @@
|
||||
use ast::visit;
|
||||
use rustc_ast as ast;
|
||||
use crate::clean;
|
||||
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_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_interface::interface;
|
||||
use rustc_span::Span;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_resolve::Resolver;
|
||||
use rustc_session::config::Externs;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
type Resolver = Rc<RefCell<interface::BoxedResolver>>;
|
||||
// Letting the resolver escape at the end of the function leads to inconsistencies between the
|
||||
// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
|
||||
// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
|
||||
crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver {
|
||||
let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
|
||||
// `walk_crate` doesn't visit the crate itself for some reason.
|
||||
crate fn early_resolve_intra_doc_links(
|
||||
resolver: &mut Resolver<'_>,
|
||||
krate: &ast::Crate,
|
||||
externs: Externs,
|
||||
) -> ResolverCaches {
|
||||
let mut loader = IntraLinkCrateLoader {
|
||||
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);
|
||||
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,
|
||||
resolver: Rc<RefCell<interface::BoxedResolver>>,
|
||||
all_traits: Vec<DefId>,
|
||||
all_trait_impls: Vec<DefId>,
|
||||
}
|
||||
|
||||
impl IntraLinkCrateLoader {
|
||||
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
|
||||
use crate::html::markdown::markdown_links;
|
||||
use crate::passes::collect_intra_doc_links::preprocess_link;
|
||||
impl IntraLinkCrateLoader<'_, '_> {
|
||||
fn fill_resolver_caches(&mut self) {
|
||||
for cnum in self.resolver.cstore().crates_untracked() {
|
||||
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
|
||||
let attrs = crate::clean::Attributes::from_ast(attrs, None);
|
||||
self.all_traits.extend(all_traits);
|
||||
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() {
|
||||
debug!(?doc);
|
||||
for link in markdown_links(doc.as_str()) {
|
||||
debug!(?link.link);
|
||||
let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
|
||||
|
||||
for link in markdown_links(&doc.as_str()) {
|
||||
let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
|
||||
x.path_str
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
self.resolver.borrow_mut().access(|resolver| {
|
||||
let _ = resolver.resolve_str_path_error(
|
||||
span,
|
||||
&path_str,
|
||||
TypeNS,
|
||||
parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
|
||||
);
|
||||
});
|
||||
let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl visit::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)
|
||||
}
|
||||
|
||||
impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
|
||||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
use rustc_ast_lowering::ResolverAstLowering;
|
||||
|
||||
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);
|
||||
if let ItemKind::Mod(..) = item.kind {
|
||||
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
|
||||
|
||||
self.load_links_in_attrs(&item.attrs, item.span);
|
||||
visit::walk_item(self, item);
|
||||
|
||||
self.current_mod = old_mod;
|
||||
} 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);
|
||||
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: visit::AssocCtxt) {
|
||||
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
|
||||
self.load_links_in_attrs(&item.attrs, item.span);
|
||||
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) {
|
||||
self.load_links_in_attrs(&field.attrs, field.span);
|
||||
visit::walk_field_def(self, field)
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &ast::Variant) {
|
||||
self.load_links_in_attrs(&v.attrs, v.span);
|
||||
visit::walk_variant(self, v)
|
||||
}
|
||||
// NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
|
||||
// then this will have to implement other visitor methods too.
|
||||
}
|
||||
|
@ -34,16 +34,18 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
|
||||
|
||||
let mut new_items = Vec::new();
|
||||
|
||||
for &cnum in cx.tcx.crates(()).iter() {
|
||||
for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
|
||||
inline::build_impl(cx, None, did, None, &mut new_items);
|
||||
// External trait impls.
|
||||
cx.with_all_trait_impls(|cx, all_trait_impls| {
|
||||
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.
|
||||
for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
|
||||
if !def_id.is_local() {
|
||||
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
|
||||
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
|
||||
for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
|
||||
if !def_id.is_local() {
|
||||
inline::build_impl(cx, None, def_id, None, &mut new_items);
|
||||
|
||||
// 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);
|
||||
new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut cleaner = BadImplStripper { prims, items: crate_items };
|
||||
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
|
||||
@ -126,36 +128,33 @@ 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`
|
||||
// doesn't work with it anyway, so pull them from the HIR map instead
|
||||
let mut extra_attrs = Vec::new();
|
||||
for trait_did in cx.tcx.all_traits() {
|
||||
for &impl_did in cx.tcx.hir().trait_impls(trait_did) {
|
||||
let impl_did = impl_did.to_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 {
|
||||
extra_attrs.extend(
|
||||
cx.tcx
|
||||
.get_attrs(did)
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::doc))
|
||||
.filter(|attr| {
|
||||
if let Some([attr]) = attr.meta_item_list().as_deref() {
|
||||
attr.has_name(sym::cfg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.cloned(),
|
||||
);
|
||||
parent = cx.tcx.parent(did);
|
||||
}
|
||||
inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items);
|
||||
extra_attrs.clear();
|
||||
});
|
||||
// Local trait impls.
|
||||
cx.with_all_trait_impls(|cx, all_trait_impls| {
|
||||
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
|
||||
let mut attr_buf = Vec::new();
|
||||
for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
|
||||
let mut parent = cx.tcx.parent(impl_def_id);
|
||||
while let Some(did) = parent {
|
||||
attr_buf.extend(
|
||||
cx.tcx
|
||||
.get_attrs(did)
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::doc))
|
||||
.filter(|attr| {
|
||||
if let Some([attr]) = attr.meta_item_list().as_deref() {
|
||||
attr.has_name(sym::cfg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.cloned(),
|
||||
);
|
||||
parent = cx.tcx.parent(did);
|
||||
}
|
||||
inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
|
||||
attr_buf.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
|
||||
items.extend(synth_impls);
|
||||
|
@ -1,7 +1,7 @@
|
||||
goto: file://|DOC_PATH|/test_docs/index.html
|
||||
// First, we check that the search results are hidden when the Escape key is pressed.
|
||||
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: ("#main-content", {"class": "content hidden"})
|
||||
press-key: "Escape"
|
||||
|
@ -5,14 +5,12 @@ write: (".search-input", "test")
|
||||
wait-for: "#titles"
|
||||
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.
|
||||
click: "#crate-search"
|
||||
// We select "lib2" option then press enter to change the filter.
|
||||
press-key: "ArrowDown"
|
||||
press-key: "Enter"
|
||||
// We now make the search again.
|
||||
write: (".search-input", "test")
|
||||
// Waiting for the search results to appear...
|
||||
wait-for: "#titles"
|
||||
// We check that there is no more "test_docs" appearing.
|
||||
|
@ -1,12 +1,12 @@
|
||||
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
|
||||
size: (433, 600)
|
||||
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": ""})
|
||||
click: (4, 280)
|
||||
click: (4, 240)
|
||||
assert-attribute: (".top-doc", {"open": ""})
|
||||
// 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 the position of the toggle on the top doc block.
|
||||
|
12
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs
Normal file
12
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs
Normal 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() {}
|
21
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
Normal file
21
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user