source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7"
+[[package]]
+name = "askama"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d8f355701c672c2ba3d718acbd213f740beea577cc4eae66accdffe15be1882"
+dependencies = [
+ "askama_derive",
+ "askama_escape",
+ "askama_shared",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84704cab5b7ae0fd3a9f78ee5eb7b27f3749df445f04623db6633459ae283267"
+dependencies = [
+ "askama_shared",
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "askama_escape"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5"
+
+[[package]]
+name = "askama_shared"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dae03eebba55a2697a376e58b573a29fe36893157173ac8df312ad85f3c0e012"
+dependencies = [
+ "askama_escape",
+ "nom",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "atty"
version = "0.2.14"
"regex",
]
-[[package]]
-name = "globwalk"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
-dependencies = [
- "bitflags",
- "ignore",
- "walkdir",
-]
-
[[package]]
name = "gsgdt"
version = "0.1.2"
"macro-utils",
]
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
[[package]]
name = "miniz_oxide"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
+[[package]]
+name = "nom"
+version = "7.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+ "version_check",
+]
+
[[package]]
name = "ntapi"
version = "0.3.6"
version = "0.0.0"
dependencies = [
"arrayvec",
+ "askama",
"expect-test",
"itertools 0.9.0",
"minifier",
"serde_json",
"smallvec",
"tempfile",
- "tera",
"tracing",
"tracing-subscriber",
"tracing-tree",
"utf-8",
]
-[[package]]
-name = "tera"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81060acb882480c8793782eb96bc86f5c83d2fc7175ad46c375c6956ef7afa62"
-dependencies = [
- "globwalk",
- "lazy_static",
- "pest",
- "pest_derive",
- "regex",
- "serde",
- "serde_json",
-]
-
[[package]]
name = "term"
version = "0.6.1"
+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`]
+- [`Result::unwrap_unchecked`]
+- [`Result::unwrap_err_unchecked`]
+- [`NonZero{unsigned}::is_power_of_two`]
+- [`File::options`]
+
+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
+[`Result::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_unchecked
+[`Result::unwrap_err_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_err_unchecked
+[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two
+[`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options
+[`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)
==========================
`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
- [Visibility modifiers (e.g. `pub`) are now syntactically allowed on trait items and
enum variants.][66183] These are still rejected semantically, but
can be seen and parsed by procedural macros and conditional compilation.
+- [You can now define a Rust `extern "C"` function with `Box<T>` and use `T*` as the corresponding
+ type on the C side.][62514] Please see [the documentation][box-memory-layout] for more information,
+ including the important caveat about preferring to avoid `Box<T>` in Rust signatures for functions defined in C.
+
+[box-memory-layout]: https://doc.rust-lang.org/std/boxed/index.html#memory-layout
Compiler
--------
[54733]: https://github.com/rust-lang/rust/pull/54733/
[61351]: https://github.com/rust-lang/rust/pull/61351/
+[62514]: https://github.com/rust-lang/rust/pull/62514/
[67255]: https://github.com/rust-lang/rust/pull/67255/
[66661]: https://github.com/rust-lang/rust/pull/66661/
[66771]: https://github.com/rust-lang/rust/pull/66771/
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
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()
+ }
+}
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};
i += 1;
}
- while i < j && lines[i].trim().is_empty() {
- i += 1;
- }
// like the first, a last line of all stars should be omitted
if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
- while j > i && lines[j - 1].trim().is_empty() {
- j -= 1;
- }
-
if i != 0 || j != lines.len() { Some((i, j)) } else { None }
}
}
pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
- State::new().to_string(f)
+ State::to_string(f)
}
pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
- State::new().to_string(|s| {
+ State::to_string(|s| {
s.print_inner_attributes(&krate.attrs);
for item in &krate.items {
s.print_item(item);
}
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
- format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
+ format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
}
impl std::ops::Deref for State<'_> {
}
fn ty_to_string(&self, ty: &ast::Ty) -> String {
- self.to_string(|s| s.print_type(ty))
+ Self::to_string(|s| s.print_type(ty))
}
fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
- self.to_string(|s| s.print_type_bounds("", bounds))
+ Self::to_string(|s| s.print_type_bounds("", bounds))
}
fn pat_to_string(&self, pat: &ast::Pat) -> String {
- self.to_string(|s| s.print_pat(pat))
+ Self::to_string(|s| s.print_pat(pat))
}
fn expr_to_string(&self, e: &ast::Expr) -> String {
- self.to_string(|s| s.print_expr(e))
+ Self::to_string(|s| s.print_expr(e))
}
fn tt_to_string(&self, tt: &TokenTree) -> String {
- self.to_string(|s| s.print_tt(tt, false))
+ Self::to_string(|s| s.print_tt(tt, false))
}
fn tts_to_string(&self, tokens: &TokenStream) -> String {
- self.to_string(|s| s.print_tts(tokens, false))
+ Self::to_string(|s| s.print_tts(tokens, false))
}
fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
- self.to_string(|s| s.print_stmt(stmt))
+ Self::to_string(|s| s.print_stmt(stmt))
}
fn item_to_string(&self, i: &ast::Item) -> String {
- self.to_string(|s| s.print_item(i))
+ Self::to_string(|s| s.print_item(i))
}
fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
- self.to_string(|s| s.print_generic_params(generic_params))
+ Self::to_string(|s| s.print_generic_params(generic_params))
}
fn path_to_string(&self, p: &ast::Path) -> String {
- self.to_string(|s| s.print_path(p, false, 0))
+ Self::to_string(|s| s.print_path(p, false, 0))
}
fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
- self.to_string(|s| s.print_path_segment(p, false))
+ Self::to_string(|s| s.print_path_segment(p, false))
}
fn vis_to_string(&self, v: &ast::Visibility) -> String {
- self.to_string(|s| s.print_visibility(v))
+ Self::to_string(|s| s.print_visibility(v))
}
fn block_to_string(&self, blk: &ast::Block) -> String {
- self.to_string(|s| {
+ Self::to_string(|s| {
// Containing cbox, will be closed by `print_block` at `}`.
s.cbox(INDENT_UNIT);
// Head-ibox, will be closed by `print_block` after `{`.
}
fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
- self.to_string(|s| s.print_meta_list_item(li))
+ Self::to_string(|s| s.print_meta_list_item(li))
}
fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
- self.to_string(|s| s.print_attr_item(ai, ai.path.span))
+ Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
}
fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
- self.to_string(|s| s.print_attribute(attr))
+ Self::to_string(|s| s.print_attribute(attr))
}
fn param_to_string(&self, arg: &ast::Param) -> String {
- self.to_string(|s| s.print_param(arg, false))
+ Self::to_string(|s| s.print_param(arg, false))
}
- fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
+ fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
let mut printer = State::new();
f(&mut printer);
printer.s.eof()
);
}
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
- self.head(self.to_string(|s| {
+ self.head(Self::to_string(|s| {
s.print_visibility(&item.vis);
s.print_unsafety(unsafety);
s.word("mod");
}
}
ast::ItemKind::ForeignMod(ref nmod) => {
- self.head(self.to_string(|s| {
+ self.head(Self::to_string(|s| {
s.print_unsafety(nmod.unsafety);
s.word("extern");
}));
ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
},
ast::VisibilityKind::Restricted { ref path, .. } => {
- let path = self.to_string(|s| s.print_path(path, false, 0));
+ let path = Self::to_string(|s| s.print_path(path, false, 0));
if path == "self" || path == "super" {
self.word_nbsp(format!("pub({})", path))
} else {
} else {
def.non_enum_variant()
};
- variant.fields[field.index()].ident.to_string()
+ variant.fields[field.index()].name.to_string()
}
ty::Tuple(_) => field.index().to_string(),
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
use smallvec::smallvec;
pub struct AsmArgs {
- templates: Vec<P<ast::Expr>>,
- operands: Vec<(ast::InlineAsmOperand, Span)>,
+ pub templates: Vec<P<ast::Expr>>,
+ pub operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
- clobber_abis: Vec<(Symbol, Span)>,
+ pub clobber_abis: Vec<(Symbol, Span)>,
options: ast::InlineAsmOptions,
- options_spans: Vec<Span>,
+ pub options_spans: Vec<Span>,
}
fn parse_args<'a>(
field_entry.set(
gimli::DW_AT_name,
- AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()),
+ AttributeValue::String(field_def.name.as_str().to_string().into_bytes()),
);
field_entry.set(
gimli::DW_AT_data_member_location,
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants.is_empty() {
- write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+ write!(&mut name, "::{}", def.variants[index].name).unwrap();
}
}
if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
use crate::value::Value;
use cstr::cstr;
+use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
// When targeting MSVC, emit MSVC style type names for compatibility with
// .natvis visualizers (and perhaps other existing native debuggers?)
- let msvc_like_names = cx.tcx.sess.target.is_like_msvc;
+ let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
let (name, encoding) = match t.kind() {
ty::Never => ("!", DW_ATE_unsigned),
ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
ty::Bool => ("bool", DW_ATE_boolean),
ty::Char => ("char", DW_ATE_unsigned_char),
- ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed),
- ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
- ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float),
+ ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
+ ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
+ ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
)
};
- if !msvc_like_names {
+ if !cpp_like_debuginfo {
return ty_metadata;
}
let name = if self.variant.ctor_kind == CtorKind::Fn {
format!("__{}", i)
} else {
- f.ident.to_string()
+ f.name.to_string()
};
let field = layout.field(cx, i);
MemberDescription {
.map(|(i, f)| {
let field = self.layout.field(cx, i);
MemberDescription {
- name: f.ident.to_string(),
+ name: f.name.to_string(),
type_metadata: type_metadata(cx, field.ty, self.span),
offset: Size::ZERO,
size: field.size,
// Enums
//=-----------------------------------------------------------------------------
-/// DWARF variant support is only available starting in LLVM 8, but
-/// on MSVC we have to use the fallback mode, because LLVM doesn't
-/// lower variant parts to PDB.
-fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
- cx.sess().target.is_like_msvc
-}
-
// FIXME(eddyb) maybe precompute this? Right now it's computed once
// per generator monomorphization, but it doesn't depend on substs.
fn generator_layout_and_saved_local_names<'tcx>(
_ => bug!(),
};
- let fallback = use_enum_fallback(cx);
+ // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+ // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+ // msvc, then we need to use a different, fallback encoding of the debuginfo.
+ let fallback = cpp_like_debuginfo(cx.tcx);
// This will always find the metadata in the type map.
let self_metadata = type_metadata(cx, self.enum_type, self.span);
impl<'tcx> VariantInfo<'_, 'tcx> {
fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
match self {
- VariantInfo::Adt(variant) => f(variant.ident.as_str()),
+ VariantInfo::Adt(variant) => f(variant.name.as_str()),
VariantInfo::Generator { variant_index, .. } => {
f(&GeneratorSubsts::variant_name(*variant_index))
}
fn variant_name(&self) -> String {
match self {
- VariantInfo::Adt(variant) => variant.ident.to_string(),
+ VariantInfo::Adt(variant) => variant.name.to_string(),
VariantInfo::Generator { variant_index, .. } => {
// Since GDB currently prints out the raw discriminant along
// with every variant, make each variant name be just the value
fn field_name(&self, i: usize) -> String {
let field_name = match *self {
VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => {
- Some(variant.fields[i].ident.name)
+ Some(variant.fields[i].name)
}
VariantInfo::Generator {
generator_layout,
let enumerators_metadata: Vec<_> = match enum_type.kind() {
ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants)
.map(|((_, discr), v)| {
- let name = v.ident.as_str();
+ let name = v.name.as_str();
let is_unsigned = match discr.ty.kind() {
ty::Int(_) => false,
ty::Uint(_) => true,
return FinalMetadata(discriminant_type_metadata(tag.value));
}
- if use_enum_fallback(cx) {
+ // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+ // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+ // msvc, then we need to use a different encoding of the debuginfo.
+ if cpp_like_debuginfo(tcx) {
let discriminant_type_metadata = match layout.variants {
Variants::Single { .. } => None,
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. }
)));
// `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
- vec![try_fn_ty, i8p, catch_fn_ty].into_iter(),
+ [try_fn_ty, i8p, catch_fn_ty].into_iter(),
tcx.types.i32,
false,
hir::Unsafety::Unsafe,
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants.is_empty() {
- write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+ write!(&mut name, "::{}", def.variants[index].name).unwrap();
}
}
if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
) {
// When targeting MSVC, emit C++ style type names for compatibility with
// .natvis visualizers (and perhaps other existing native debuggers?)
- let cpp_like_names = cpp_like_names(tcx);
+ let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
match *t.kind() {
ty::Bool => output.push_str("bool"),
ty::Char => output.push_str("char"),
ty::Str => output.push_str("str"),
ty::Never => {
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push_str("never$");
} else {
output.push('!');
ty::Float(float_ty) => output.push_str(float_ty.name_str()),
ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
ty::Adt(def, substs) => {
- if def.is_enum() && cpp_like_names {
+ if def.is_enum() && cpp_like_debuginfo {
msvc_enum_fallback(tcx, t, def, substs, output, visited);
} else {
push_item_name(tcx, def.did, qualified, output);
}
}
ty::Tuple(component_types) => {
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push_str("tuple$<");
} else {
output.push('(');
for component_type in component_types {
push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
- push_arg_separator(cpp_like_names, output);
+ push_arg_separator(cpp_like_debuginfo, output);
}
if !component_types.is_empty() {
pop_arg_separator(output);
}
- if cpp_like_names {
- push_close_angle_bracket(cpp_like_names, output);
+ if cpp_like_debuginfo {
+ push_close_angle_bracket(cpp_like_debuginfo, output);
} else {
output.push(')');
}
}
ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
- if cpp_like_names {
+ if cpp_like_debuginfo {
match mutbl {
hir::Mutability::Not => output.push_str("ptr_const$<"),
hir::Mutability::Mut => output.push_str("ptr_mut$<"),
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
- if cpp_like_names {
- push_close_angle_bracket(cpp_like_names, output);
+ if cpp_like_debuginfo {
+ push_close_angle_bracket(cpp_like_debuginfo, output);
}
}
ty::Ref(_, inner_type, mutbl) => {
// types out to aid debugging in MSVC.
let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
- if !cpp_like_names {
+ if !cpp_like_debuginfo {
output.push('&');
output.push_str(mutbl.prefix_str());
} else if !is_slice_or_str {
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
- if cpp_like_names && !is_slice_or_str {
- push_close_angle_bracket(cpp_like_names, output);
+ if cpp_like_debuginfo && !is_slice_or_str {
+ push_close_angle_bracket(cpp_like_debuginfo, output);
}
}
ty::Array(inner_type, len) => {
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push_str("array$<");
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
match len.val {
}
}
ty::Slice(inner_type) => {
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push_str("slice$<");
} else {
output.push('[');
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
- if cpp_like_names {
- push_close_angle_bracket(cpp_like_names, output);
+ if cpp_like_debuginfo {
+ push_close_angle_bracket(cpp_like_debuginfo, output);
} else {
output.push(']');
}
ty::Dynamic(ref trait_data, ..) => {
let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
- let has_enclosing_parens = if cpp_like_names {
+ let has_enclosing_parens = if cpp_like_debuginfo {
output.push_str("dyn$<");
false
} else {
}
for (item_def_id, ty) in projection_bounds {
- push_arg_separator(cpp_like_names, output);
+ push_arg_separator(cpp_like_debuginfo, output);
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push_str("assoc$<");
push_item_name(tcx, item_def_id, false, output);
- push_arg_separator(cpp_like_names, output);
+ push_arg_separator(cpp_like_debuginfo, output);
push_debuginfo_type_name(tcx, ty, true, output, visited);
- push_close_angle_bracket(cpp_like_names, output);
+ push_close_angle_bracket(cpp_like_debuginfo, output);
} else {
push_item_name(tcx, item_def_id, false, output);
output.push('=');
}
}
- push_close_angle_bracket(cpp_like_names, output);
+ push_close_angle_bracket(cpp_like_debuginfo, output);
}
if auto_traits.len() != 0 {
- push_auto_trait_separator(cpp_like_names, output);
+ push_auto_trait_separator(cpp_like_debuginfo, output);
}
}
for auto_trait in auto_traits {
output.push_str(&auto_trait);
- push_auto_trait_separator(cpp_like_names, output);
+ push_auto_trait_separator(cpp_like_debuginfo, output);
}
pop_auto_trait_separator(output);
}
- if cpp_like_names {
- push_close_angle_bracket(cpp_like_names, output);
+ if cpp_like_debuginfo {
+ push_close_angle_bracket(cpp_like_debuginfo, output);
} else if has_enclosing_parens {
output.push(')');
}
// use a dummy string that should make it clear
// that something unusual is going on
if !visited.insert(t) {
- output.push_str(if cpp_like_names {
+ output.push_str(if cpp_like_debuginfo {
"recursive_type$"
} else {
"<recursive_type>"
let sig =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
- if cpp_like_names {
+ if cpp_like_debuginfo {
// Format as a C++ function pointer: return_type (*)(params...)
if sig.output().is_unit() {
output.push_str("void");
if !sig.inputs().is_empty() {
for ¶meter_type in sig.inputs() {
push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
- push_arg_separator(cpp_like_names, output);
+ push_arg_separator(cpp_like_debuginfo, output);
}
pop_arg_separator(output);
}
output.push(')');
- if !cpp_like_names && !sig.output().is_unit() {
+ if !cpp_like_debuginfo && !sig.output().is_unit() {
output.push_str(" -> ");
push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
}
let max = dataful_discriminant_range.end;
let max = tag.value.size(&tcx).truncate(max);
- let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+ let dataful_variant_name = def.variants[*dataful_variant].name.as_str();
output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
} else if let Variants::Single { index: variant_idx } = &layout.variants {
// Uninhabited enums can't be constructed and should never need to be visualized so
// skip this step for them.
if def.variants.len() != 0 {
- let variant = def.variants[*variant_idx].ident.as_str();
+ let variant = def.variants[*variant_idx].name.as_str();
output.push_str(&format!(", {}", variant));
}
const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
- fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
- if cpp_like_names {
- push_arg_separator(cpp_like_names, output);
+ fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
+ if cpp_like_debuginfo {
+ push_arg_separator(cpp_like_debuginfo, output);
} else {
output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
}
t: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> String {
- let cpp_like_names = cpp_like_names(tcx);
+ let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
let mut vtable_name = String::with_capacity(64);
- if cpp_like_names {
+ if cpp_like_debuginfo {
vtable_name.push_str("impl$<");
} else {
vtable_name.push('<');
let mut visited = FxHashSet::default();
push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
- if cpp_like_names {
+ if cpp_like_debuginfo {
vtable_name.push_str(", ");
} else {
vtable_name.push_str(" as ");
vtable_name.push_str("_");
}
- push_close_angle_bracket(cpp_like_names, &mut vtable_name);
+ push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
- let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" };
+ let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" };
vtable_name.reserve_exact(suffix.len());
vtable_name.push_str(suffix);
DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
// Generators look like closures, but we want to treat them differently
// in the debug info.
- if cpp_like_names(tcx) {
+ if cpp_like_debuginfo(tcx) {
write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
} else {
write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
output.push_str(name.as_str());
}
DefPathDataName::Anon { namespace } => {
- if cpp_like_names(tcx) {
+ if cpp_like_debuginfo(tcx) {
write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
} else {
write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
- let cpp_like_names = cpp_like_names(tcx);
+ let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
output.push('<');
other => bug!("Unexpected non-erasable generic: {:?}", other),
}
- push_arg_separator(cpp_like_names, output);
+ push_arg_separator(cpp_like_debuginfo, output);
}
pop_arg_separator(output);
- push_close_angle_bracket(cpp_like_names, output);
+ push_close_angle_bracket(cpp_like_debuginfo, output);
true
}
// avoiding collisions and will make the emitted type names shorter.
let hash: u64 = hasher.finish();
- if cpp_like_names(tcx) {
+ if cpp_like_debuginfo(tcx) {
write!(output, "CONST${:x}", hash)
} else {
write!(output, "{{CONST#{:x}}}", hash)
push_generic_params_internal(tcx, substs, output, &mut visited);
}
-fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) {
+fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
// so add a space to avoid confusion.
- if cpp_like_names && output.ends_with('>') {
+ if cpp_like_debuginfo && output.ends_with('>') {
output.push(' ')
};
}
}
-fn push_arg_separator(cpp_like_names: bool, output: &mut String) {
+fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
// Natvis does not always like having spaces between parts of the type name
// and this causes issues when we need to write a typename in natvis, for example
// as part of a cast like the `HashMap` visualizer does.
- if cpp_like_names {
+ if cpp_like_debuginfo {
output.push(',');
} else {
output.push_str(", ");
output.pop();
}
-fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
+/// Check if we should generate C++ like names and debug information.
+pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
tcx.sess.target.is_like_msvc
}
match layout.variants {
Variants::Single { index } => {
// Inside a variant
- PathElem::Field(def.variants[index].fields[field].ident.name)
+ PathElem::Field(def.variants[index].fields[field].name)
}
Variants::Multiple { .. } => bug!("we handled variants above"),
}
}
// other ADTs
- ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
+ ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].name),
// arrays/slices
ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field),
new_op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let name = match old_op.layout.ty.kind() {
- ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
+ ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].name),
// Generators also have variants
ty::Generator(..) => PathElem::GeneratorState(variant_id),
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
param_env,
Binder::dummy(TraitPredicate {
trait_ref,
- constness: ty::BoundConstness::ConstIfConst,
+ constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
}),
);
return;
}
Ok(Some(ImplSource::UserDefined(data))) => {
+ if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
+ self.check_op(ops::FnCallNonConst(None));
+ return;
+ }
let callee_name = tcx.item_name(callee);
if let Some(&did) = tcx
.associated_item_def_ids(data.impl_def_id)
}
}
}
+
+#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
+pub enum NodeIdHashingMode {
+ Ignore,
+ HashDefPath,
+}
+
+/// Controls what data we do or not not hash.
+/// Whenever a `HashStable` implementation caches its
+/// result, it needs to include `HashingControls` as part
+/// of the key, to ensure that is does not produce an incorrect
+/// result (for example, using a `Fingerprint` produced while
+/// hashing `Span`s when a `Fingeprint` without `Span`s is
+/// being requested)
+#[derive(Clone, Hash, Eq, PartialEq, Debug)]
+pub struct HashingControls {
+ pub hash_spans: bool,
+ pub node_id_hashing_mode: NodeIdHashingMode,
+}
fn test_from_iterator() {
assert_eq!(std::iter::empty().collect::<ThinVec<String>>().into_vec(), Vec::<String>::new());
assert_eq!(std::iter::once(42).collect::<ThinVec<_>>().into_vec(), vec![42]);
- assert_eq!(vec![1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
- assert_eq!(vec![1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
+ assert_eq!([1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
+ assert_eq!([1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
}
#[test]
);
assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
assert_eq!(
- vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
+ [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
vec![(1, true), (2, false)]
);
}
#[test]
fn test_get() {
- let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
+ let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
assert_eq!(v.get(&1), Some(&true));
assert_eq!(v.get(&2), Some(&false));
assert_eq!(v.get(&3), None);
let backtrace_step = backtrace.next().map(|bt| {
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
let def_site_span =
- Self::from_span_full(bt.def_site, false, None, None, vec![].into_iter(), je);
+ Self::from_span_full(bt.def_site, false, None, None, [].into_iter(), je);
Box::new(DiagnosticSpanMacroExpansion {
span: call_site,
macro_decl_name: bt.kind.descr(),
/// Annotation under a single line of code
Singleline,
- /// Annotation enclosing the first and last character of a multiline span
- Multiline(MultilineAnnotation),
-
// The Multiline type above is replaced with the following three in order
// to reuse the current label drawing code.
//
}
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);
}
}
- 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();
}
}
- 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 }
}
/// 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,
/// 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));
});
/// 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];
}
}
}
- 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);
}
use crate::base::*;
use crate::config::StripUnconfigured;
-use crate::configure;
use crate::hygiene::SyntaxContext;
use crate::mbe::macro_rules::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
-use rustc_ast::{NodeId, PatKind, Path, StmtKind};
+use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind};
+use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
+use rustc_ast::{NodeId, PatKind, StmtKind, TyKind};
use rustc_ast_pretty::pprust;
use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
-use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
use rustc_span::{FileName, LocalExpnId, Span};
use smallvec::SmallVec;
-use std::ops::DerefMut;
+use std::ops::Deref;
use std::path::PathBuf;
use std::rc::Rc;
use std::{iter, mem};
}
})*
+ fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
+ T::fragment_to_output(self)
+ }
+
pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
match self {
AstFragment::OptExpr(opt_expr) => {
Arms(SmallVec<[ast::Arm; 1]>) {
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
}
- Fields(SmallVec<[ast::ExprField; 1]>) {
+ ExprFields(SmallVec<[ast::ExprField; 1]>) {
"field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
}
- FieldPats(SmallVec<[ast::PatField; 1]>) {
+ PatFields(SmallVec<[ast::PatField; 1]>) {
"field pattern";
many fn flat_map_pat_field;
fn visit_pat_field();
Params(SmallVec<[ast::Param; 1]>) {
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
}
- StructFields(SmallVec<[ast::FieldDef; 1]>) {
+ FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
"field";
many fn flat_map_field_def;
fn visit_field_def();
| AstFragmentKind::ForeignItems
| AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
AstFragmentKind::Arms
- | AstFragmentKind::Fields
- | AstFragmentKind::FieldPats
+ | AstFragmentKind::ExprFields
+ | AstFragmentKind::PatFields
| AstFragmentKind::GenericParams
| AstFragmentKind::Params
- | AstFragmentKind::StructFields
+ | AstFragmentKind::FieldDefs
| AstFragmentKind::Variants => SupportsMacroExpansion::No,
}
}
AstFragmentKind::Arms => {
AstFragment::Arms(items.map(Annotatable::expect_arm).collect())
}
- AstFragmentKind::Fields => {
- AstFragment::Fields(items.map(Annotatable::expect_expr_field).collect())
+ AstFragmentKind::ExprFields => {
+ AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect())
}
- AstFragmentKind::FieldPats => {
- AstFragment::FieldPats(items.map(Annotatable::expect_pat_field).collect())
+ AstFragmentKind::PatFields => {
+ AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect())
}
AstFragmentKind::GenericParams => {
AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect())
AstFragmentKind::Params => {
AstFragment::Params(items.map(Annotatable::expect_param).collect())
}
- AstFragmentKind::StructFields => {
- AstFragment::StructFields(items.map(Annotatable::expect_field_def).collect())
+ AstFragmentKind::FieldDefs => {
+ AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect())
}
AstFragmentKind::Variants => {
AstFragment::Variants(items.map(Annotatable::expect_variant).collect())
pos: usize,
item: Annotatable,
// Required for resolving derive helper attributes.
- derives: Vec<Path>,
+ derives: Vec<ast::Path>,
},
Derive {
- path: Path,
+ path: ast::Path,
item: Annotatable,
},
}
krate,
),
Annotatable::Item(item_inner)
- if matches!(attr.style, ast::AttrStyle::Inner)
+ if matches!(attr.style, AttrStyle::Inner)
&& matches!(
item_inner.kind,
ItemKind::Mod(
if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item);
}
- let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
+ let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
ExpandResult::Retry(item) => {
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind {
- ast::ItemKind::Mod(_, mod_kind)
+ ItemKind::Mod(_, mod_kind)
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
{
feature_err(
&mut self,
toks: TokenStream,
kind: AstFragmentKind,
- path: &Path,
+ path: &ast::Path,
span: Span,
) -> AstFragment {
let mut parser = self.cx.new_parser_from_tts(toks);
)?),
AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
AstFragmentKind::Arms
- | AstFragmentKind::Fields
- | AstFragmentKind::FieldPats
+ | AstFragmentKind::ExprFields
+ | AstFragmentKind::PatFields
| AstFragmentKind::GenericParams
| AstFragmentKind::Params
- | AstFragmentKind::StructFields
+ | AstFragmentKind::FieldDefs
| AstFragmentKind::Variants => panic!("unexpected AST fragment kind"),
})
}
pub fn ensure_complete_parse<'a>(
this: &mut Parser<'a>,
- macro_path: &Path,
+ macro_path: &ast::Path,
kind_name: &str,
span: Span,
) {
}
}
+/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// for an AST node that supports attributes
+/// (see the `Annotatable` enum)
+/// This method assigns a `NodeId`, and sets that `NodeId`
+/// as our current 'lint node id'. If a macro call is found
+/// inside this AST node, we will use this AST node's `NodeId`
+/// to emit lints associated with that macro (allowing
+/// `#[allow]` / `#[deny]` to be applied close to
+/// the macro invocation).
+///
+/// Do *not* call this for a macro AST node
+/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
+/// at these AST nodes, since they are removed and
+/// replaced with the result of macro expansion.
+///
+/// All other `NodeId`s are assigned by `visit_id`.
+/// * `self` is the 'self' parameter for the current method,
+/// * `id` is a mutable reference to the `NodeId` field
+/// of the current AST node.
+/// * `closure` is a closure that executes the
+/// `noop_visit_*` / `noop_flat_map_*` method
+/// for the current AST node.
+macro_rules! assign_id {
+ ($self:ident, $id:expr, $closure:expr) => {{
+ let old_id = $self.cx.current_expansion.lint_node_id;
+ if $self.monotonic {
+ debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
+ let new_id = $self.cx.resolver.next_node_id();
+ *$id = new_id;
+ $self.cx.current_expansion.lint_node_id = new_id;
+ }
+ let ret = ($closure)();
+ $self.cx.current_expansion.lint_node_id = old_id;
+ ret
+ }};
+}
+
+enum AddSemicolon {
+ Yes,
+ No,
+}
+
+/// A trait implemented for all `AstFragment` nodes and providing all pieces
+/// of functionality used by `InvocationCollector`.
+trait InvocationCollectorNode: AstLike {
+ type OutputTy = SmallVec<[Self; 1]>;
+ type AttrsTy: Deref<Target = [ast::Attribute]> = Vec<ast::Attribute>;
+ const KIND: AstFragmentKind;
+ fn to_annotatable(self) -> Annotatable;
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
+ fn id(&mut self) -> &mut NodeId;
+ fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
+ unreachable!()
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, _visitor: &mut V) {
+ unreachable!()
+ }
+ fn is_mac_call(&self) -> bool {
+ false
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ unreachable!()
+ }
+ fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
+ fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
+ }
+ fn wrap_flat_map_node_noop_flat_map(
+ node: Self,
+ collector: &mut InvocationCollector<'_, '_>,
+ noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+ ) -> Result<Self::OutputTy, Self> {
+ Ok(noop_flat_map(node, collector))
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Item> {
+ const KIND: AstFragmentKind = AstFragmentKind::Items;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Item(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_item(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+ fn wrap_flat_map_node_noop_flat_map(
+ mut node: Self,
+ collector: &mut InvocationCollector<'_, '_>,
+ noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+ ) -> Result<Self::OutputTy, Self> {
+ if !matches!(node.kind, ItemKind::Mod(..)) {
+ return Ok(noop_flat_map(node, collector));
+ }
+
+ // Work around borrow checker not seeing through `P`'s deref.
+ let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs));
+ let ItemKind::Mod(_, mod_kind) = &mut node.kind else {
+ unreachable!()
+ };
+
+ let ecx = &mut collector.cx;
+ let (file_path, dir_path, dir_ownership) = match mod_kind {
+ ModKind::Loaded(_, inline, _) => {
+ // Inline `mod foo { ... }`, but we still need to push directories.
+ let (dir_path, dir_ownership) = mod_dir_path(
+ &ecx.sess,
+ ident,
+ &attrs,
+ &ecx.current_expansion.module,
+ ecx.current_expansion.dir_ownership,
+ *inline,
+ );
+ node.attrs = attrs;
+ (None, dir_path, dir_ownership)
+ }
+ ModKind::Unloaded => {
+ // We have an outline `mod foo;` so we need to parse the file.
+ let old_attrs_len = attrs.len();
+ let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } =
+ parse_external_mod(
+ &ecx.sess,
+ ident,
+ span,
+ &ecx.current_expansion.module,
+ ecx.current_expansion.dir_ownership,
+ &mut attrs,
+ );
+
+ if let Some(extern_mod_loaded) = ecx.extern_mod_loaded {
+ (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
+ }
+
+ *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
+ node.attrs = attrs;
+ if node.attrs.len() > old_attrs_len {
+ // If we loaded an out-of-line module and added some inner attributes,
+ // then we need to re-configure it and re-collect attributes for
+ // resolution and expansion.
+ return Err(node);
+ }
+ (Some(file_path), dir_path, dir_ownership)
+ }
+ };
+
+ // Set the module info before we flat map.
+ let mut module = ecx.current_expansion.module.with_dir_path(dir_path);
+ module.mod_path.push(ident);
+ if let Some(file_path) = file_path {
+ module.file_path_stack.push(file_path);
+ }
+
+ let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module));
+ let orig_dir_ownership =
+ mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
+
+ let res = Ok(noop_flat_map(node, collector));
+
+ collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
+ collector.cx.current_expansion.module = orig_module;
+ res
+ }
+}
+
+struct TraitItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag> {
+ type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+ const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::TraitItem(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_trait_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_assoc_item(self.wrapped, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let item = self.wrapped.into_inner();
+ match item.kind {
+ AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+struct ImplItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, ImplItemTag> {
+ type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+ const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ImplItem(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_impl_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_assoc_item(self.wrapped, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let item = self.wrapped.into_inner();
+ match item.kind {
+ AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::ForeignItem> {
+ const KIND: AstFragmentKind = AstFragmentKind::ForeignItems;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ForeignItem(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_foreign_items()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_foreign_item(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ForeignItemKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for ast::Variant {
+ const KIND: AstFragmentKind = AstFragmentKind::Variants;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Variant(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_variants()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_variant(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::FieldDef {
+ const KIND: AstFragmentKind = AstFragmentKind::FieldDefs;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::FieldDef(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_field_defs()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_field_def(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::PatField {
+ const KIND: AstFragmentKind = AstFragmentKind::PatFields;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::PatField(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_pat_fields()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_pat_field(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::ExprField {
+ const KIND: AstFragmentKind = AstFragmentKind::ExprFields;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::ExprField(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_expr_fields()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_expr_field(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Param {
+ const KIND: AstFragmentKind = AstFragmentKind::Params;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Param(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_params()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_param(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::GenericParam {
+ const KIND: AstFragmentKind = AstFragmentKind::GenericParams;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::GenericParam(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_generic_params()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_generic_param(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Arm {
+ const KIND: AstFragmentKind = AstFragmentKind::Arms;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Arm(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_arms()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_arm(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for ast::Stmt {
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::Stmts;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Stmt(P(self))
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_stmts()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+ noop_flat_map_stmt(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ match &self.kind {
+ StmtKind::MacCall(..) => true,
+ StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
+ StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
+ StmtKind::Expr(..) => unreachable!(),
+ StmtKind::Local(..) | StmtKind::Empty => false,
+ }
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ // We pull macro invocations (both attributes and fn-like macro calls) out of their
+ // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
+ let (add_semicolon, mac, attrs) = match self.kind {
+ StmtKind::MacCall(mac) => {
+ let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
+ (style == MacStmtStyle::Semicolon, mac, attrs)
+ }
+ StmtKind::Item(item) => match item.into_inner() {
+ ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
+ (mac.args.need_semicolon(), mac, attrs.into())
+ }
+ _ => unreachable!(),
+ },
+ StmtKind::Semi(expr) => match expr.into_inner() {
+ ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {
+ (mac.args.need_semicolon(), mac, attrs)
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ };
+ (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
+ }
+ fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
+ // If this is a macro invocation with a semicolon, then apply that
+ // semicolon to the final statement produced by expansion.
+ if matches!(add_semicolon, AddSemicolon::Yes) {
+ if let Some(stmt) = stmts.pop() {
+ stmts.push(stmt.add_trailing_semicolon());
+ }
+ }
+ }
+}
+
+impl InvocationCollectorNode for ast::Crate {
+ type OutputTy = ast::Crate;
+ const KIND: AstFragmentKind = AstFragmentKind::Crate;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Crate(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_crate()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_crate(self, visitor)
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Ty> {
+ type OutputTy = P<ast::Ty>;
+ const KIND: AstFragmentKind = AstFragmentKind::Ty;
+ fn to_annotatable(self) -> Annotatable {
+ unreachable!()
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_ty()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_ty(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ast::TyKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Pat> {
+ type OutputTy = P<ast::Pat>;
+ const KIND: AstFragmentKind = AstFragmentKind::Pat;
+ fn to_annotatable(self) -> Annotatable {
+ unreachable!()
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_pat()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_pat(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, PatKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl InvocationCollectorNode for P<ast::Expr> {
+ type OutputTy = P<ast::Expr>;
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::Expr;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Expr(self)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_expr()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.id
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_expr(self, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.kind, ExprKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.into_inner();
+ match node.kind {
+ ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
+struct OptExprTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::Expr>, OptExprTag> {
+ type OutputTy = Option<P<ast::Expr>>;
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Expr(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ fragment.make_opt_expr()
+ }
+ fn id(&mut self) -> &mut NodeId {
+ &mut self.wrapped.id
+ }
+ fn noop_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
+ noop_visit_expr(&mut self.wrapped, visitor);
+ Some(self.wrapped)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+ let node = self.wrapped.into_inner();
+ match node.kind {
+ ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+ fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {
+ cfg.maybe_emit_expr_attr_err(&attr);
+ }
+}
+
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
cfg: StripUnconfigured<'a>,
fn collect_attr(
&mut self,
- (attr, pos, derives): (ast::Attribute, usize, Vec<Path>),
+ (attr, pos, derives): (ast::Attribute, usize, Vec<ast::Path>),
item: Annotatable,
kind: AstFragmentKind,
) -> AstFragment {
/// its position and derives following it. We have to collect the derives in order to resolve
/// legacy derive helpers (helpers written before derives that introduce them).
fn take_first_attr(
- &mut self,
+ &self,
item: &mut impl AstLike,
- ) -> Option<(ast::Attribute, usize, Vec<Path>)> {
+ ) -> Option<(ast::Attribute, usize, Vec<ast::Path>)> {
let mut attr = None;
item.visit_attrs(|attrs| {
attr
}
- fn take_stmt_bang(
- &mut self,
- stmt: ast::Stmt,
- ) -> Result<(bool, MacCall, Vec<ast::Attribute>), ast::Stmt> {
- match stmt.kind {
- StmtKind::MacCall(mac) => {
- let MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
- Ok((style == MacStmtStyle::Semicolon, mac, attrs.into()))
- }
- StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => {
- match item.into_inner() {
- ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
- Ok((mac.args.need_semicolon(), mac, attrs))
- }
- _ => unreachable!(),
- }
- }
- StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
- match expr.into_inner() {
- ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
- Ok((mac.args.need_semicolon(), mac, attrs.into()))
- }
- _ => unreachable!(),
- }
- }
- StmtKind::Local(..) | StmtKind::Empty | StmtKind::Item(..) | StmtKind::Semi(..) => {
- Err(stmt)
- }
- StmtKind::Expr(..) => unreachable!(),
- }
- }
-
fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
self.cfg.configure(node)
}
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
- fn check_attributes(&self, attrs: &[ast::Attribute], call: &MacCall) {
+ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let features = self.cx.ecfg.features.unwrap();
let mut attrs = attrs.iter().peekable();
let mut span: Option<Span> = None;
}
}
}
-}
-/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
-/// for an AST node that supports attributes
-/// (see the `Annotatable` enum)
-/// This method assigns a `NodeId`, and sets that `NodeId`
-/// as our current 'lint node id'. If a macro call is found
-/// inside this AST node, we will use this AST node's `NodeId`
-/// to emit lints associated with that macro (allowing
-/// `#[allow]` / `#[deny]` to be applied close to
-/// the macro invocation).
-///
-/// Do *not* call this for a macro AST node
-/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
-/// at these AST nodes, since they are removed and
-/// replaced with the result of macro expansion.
-///
-/// All other `NodeId`s are assigned by `visit_id`.
-/// * `self` is the 'self' parameter for the current method,
-/// * `id` is a mutable reference to the `NodeId` field
-/// of the current AST node.
-/// * `closure` is a closure that executes the
-/// `noop_visit_*` / `noop_flat_map_*` method
-/// for the current AST node.
-macro_rules! assign_id {
- ($self:ident, $id:expr, $closure:expr) => {{
- let old_id = $self.cx.current_expansion.lint_node_id;
- if $self.monotonic {
- debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
- let new_id = $self.cx.resolver.next_node_id();
- *$id = new_id;
- $self.cx.current_expansion.lint_node_id = new_id;
+ fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
+ &mut self,
+ node: Node,
+ ) -> Node::OutputTy {
+ let mut node = configure!(self, node);
+
+ if let Some(attr) = self.take_first_attr(&mut node) {
+ Node::pre_flat_map_node_collect_attr(&self.cfg, &attr.0);
+ self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::<Node>()
+ } else if node.is_mac_call() {
+ let (mac, attrs, add_semicolon) = node.take_mac_call();
+ self.check_attributes(&attrs, &mac);
+ let mut res = self.collect_bang(mac, Node::KIND).make_ast::<Node>();
+ Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
+ res
+ } else {
+ match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
+ assign_id!(this, node.id(), || node.noop_flat_map(this))
+ }) {
+ Ok(output) => output,
+ Err(node) => self.flat_map_node(node),
+ }
}
- let ret = ($closure)();
- $self.cx.current_expansion.lint_node_id = old_id;
- ret
- }};
+ }
+
+ fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
+ &mut self,
+ node: &mut Node,
+ ) {
+ if let Some(attr) = self.take_first_attr(node) {
+ visit_clobber(node, |node| {
+ self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::<Node>()
+ })
+ } else if node.is_mac_call() {
+ visit_clobber(node, |node| {
+ // Do not clobber unless it's actually a macro (uncommon case).
+ let (mac, attrs, _) = node.take_mac_call();
+ self.check_attributes(&attrs, &mac);
+ self.collect_bang(mac, Node::KIND).make_ast::<Node>()
+ })
+ } else {
+ assign_id!(self, node.id(), || node.noop_visit(self))
+ }
+ }
}
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
- fn visit_crate(&mut self, krate: &mut ast::Crate) {
- visit_clobber(krate, |krate| {
- let span = krate.span;
- let mut krate = match self.configure(krate) {
- Some(krate) => krate,
- None => {
- return ast::Crate {
- attrs: Vec::new(),
- items: Vec::new(),
- span,
- id: self.cx.resolver.next_node_id(),
- is_placeholder: false,
- };
- }
- };
-
- if let Some(attr) = self.take_first_attr(&mut krate) {
- return self
- .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
- .make_crate();
- }
-
- assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self));
- krate
- })
+ fn flat_map_item(&mut self, node: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+ self.flat_map_node(node)
}
- fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
- self.cfg.configure_expr(expr);
- visit_clobber(expr.deref_mut(), |mut expr| {
- if let Some(attr) = self.take_first_attr(&mut expr) {
- // Collect the invoc regardless of whether or not attributes are permitted here
- // expansion will eat the attribute so it won't error later.
- self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
- // AstFragmentKind::Expr requires the macro to emit an expression.
- return self
- .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
- .make_expr()
- .into_inner();
- }
-
- if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs, &mac);
- self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner()
- } else {
- assign_id!(self, &mut expr.id, || {
- ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
- });
- expr
- }
- });
+ fn flat_map_trait_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+ self.flat_map_node(AstLikeWrapper::new(node, TraitItemTag))
}
- fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
- let mut arm = configure!(self, arm);
-
- if let Some(attr) = self.take_first_attr(&mut arm) {
- return self
- .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
- .make_arms();
- }
-
- assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
+ fn flat_map_impl_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+ self.flat_map_node(AstLikeWrapper::new(node, ImplItemTag))
}
- fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
- let mut field = configure!(self, field);
-
- if let Some(attr) = self.take_first_attr(&mut field) {
- return self
- .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields)
- .make_expr_fields();
- }
-
- assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
+ fn flat_map_foreign_item(
+ &mut self,
+ node: P<ast::ForeignItem>,
+ ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
+ self.flat_map_node(node)
}
- fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
- let mut fp = configure!(self, fp);
-
- if let Some(attr) = self.take_first_attr(&mut fp) {
- return self
- .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats)
- .make_pat_fields();
- }
-
- assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
+ fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
+ self.flat_map_node(node)
}
- fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
- let mut p = configure!(self, p);
-
- if let Some(attr) = self.take_first_attr(&mut p) {
- return self
- .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
- .make_params();
- }
-
- assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
+ fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
+ self.flat_map_node(node)
}
- fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
- let mut sf = configure!(self, sf);
-
- if let Some(attr) = self.take_first_attr(&mut sf) {
- return self
- .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields)
- .make_field_defs();
- }
-
- assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
+ fn flat_map_pat_field(&mut self, node: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
+ self.flat_map_node(node)
}
- fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
- let mut variant = configure!(self, variant);
-
- if let Some(attr) = self.take_first_attr(&mut variant) {
- return self
- .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
- .make_variants();
- }
-
- assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
+ fn flat_map_expr_field(&mut self, node: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
+ self.flat_map_node(node)
}
- fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
- let expr = configure!(self, expr);
- expr.filter_map(|mut expr| {
- if let Some(attr) = self.take_first_attr(&mut expr) {
- self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
- return self
- .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
- .make_opt_expr()
- .map(|expr| expr.into_inner());
- }
-
- if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs, &mac);
- self.collect_bang(mac, AstFragmentKind::OptExpr)
- .make_opt_expr()
- .map(|expr| expr.into_inner())
- } else {
- assign_id!(self, &mut expr.id, || {
- Some({
- noop_visit_expr(&mut expr, self);
- expr
- })
- })
- }
- })
+ fn flat_map_param(&mut self, node: ast::Param) -> SmallVec<[ast::Param; 1]> {
+ self.flat_map_node(node)
}
- fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
- match pat.kind {
- PatKind::MacCall(_) => {}
- _ => return noop_visit_pat(pat, self),
- }
-
- visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
- PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(),
- _ => unreachable!(),
- });
+ fn flat_map_generic_param(
+ &mut self,
+ node: ast::GenericParam,
+ ) -> SmallVec<[ast::GenericParam; 1]> {
+ self.flat_map_node(node)
}
- fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
- let mut stmt = configure!(self, stmt);
+ fn flat_map_arm(&mut self, node: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
+ self.flat_map_node(node)
+ }
- // We pull macro invocations (both attributes and fn-like macro calls) out of their
- // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
+ fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
// FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
// changing that requires some compatibility measures.
- let mut stmt = if !stmt.is_expr() {
- if let Some(attr) = self.take_first_attr(&mut stmt) {
- return self
- .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
- .make_stmts();
- }
-
- match self.take_stmt_bang(stmt) {
- Ok((add_semicolon, mac, attrs)) => {
- self.check_attributes(&attrs, &mac);
- let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts();
-
- // If this is a macro invocation with a semicolon, then apply that
- // semicolon to the final statement produced by expansion.
- if add_semicolon {
- if let Some(stmt) = stmts.pop() {
- stmts.push(stmt.add_trailing_semicolon());
- }
- }
-
- return stmts;
+ if node.is_expr() {
+ // The only way that we can end up with a `MacCall` expression statement,
+ // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
+ // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+ // Record this information, so that we can report a more specific
+ // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
+ // See #78991 for an investigation of treating macros in this position
+ // as statements, rather than expressions, during parsing.
+ let mut node = configure!(self, node);
+ return match &node.kind {
+ StmtKind::Expr(expr)
+ if matches!(**expr, ast::Expr { kind: ExprKind::MacCall(..), .. }) =>
+ {
+ self.cx.current_expansion.is_trailing_mac = true;
+ // Don't use `assign_id` for this statement - it may get removed
+ // entirely due to a `#[cfg]` on the contained expression
+ let res = noop_flat_map_stmt(node, self);
+ self.cx.current_expansion.is_trailing_mac = false;
+ res
}
- Err(stmt) => stmt,
- }
- } else {
- stmt
- };
-
- // The only way that we can end up with a `MacCall` expression statement,
- // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
- // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
- // Record this information, so that we can report a more specific
- // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
- // See #78991 for an investigation of treating macros in this position
- // as statements, rather than expressions, during parsing.
- let res = match &stmt.kind {
- StmtKind::Expr(expr)
- if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
- {
- self.cx.current_expansion.is_trailing_mac = true;
- // Don't use `assign_id` for this statement - it may get removed
- // entirely due to a `#[cfg]` on the contained expression
- noop_flat_map_stmt(stmt, self)
- }
- _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
- };
- self.cx.current_expansion.is_trailing_mac = false;
- res
- }
-
- fn visit_block(&mut self, block: &mut P<Block>) {
- let orig_dir_ownership = mem::replace(
- &mut self.cx.current_expansion.dir_ownership,
- DirOwnership::UnownedViaBlock,
- );
- noop_visit_block(block, self);
- self.cx.current_expansion.dir_ownership = orig_dir_ownership;
- }
-
- fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
- .make_items();
+ _ => assign_id!(self, &mut node.id, || noop_flat_map_stmt(node, self)),
+ };
}
- let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck.
- let ident = item.ident;
- let span = item.span;
-
- match item.kind {
- ast::ItemKind::MacCall(ref mac) => {
- self.check_attributes(&attrs, &mac);
- item.attrs = attrs;
- item.and_then(|item| match item.kind {
- ItemKind::MacCall(mac) => {
- self.collect_bang(mac, AstFragmentKind::Items).make_items()
- }
- _ => unreachable!(),
- })
- }
- ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => {
- let (file_path, dir_path, dir_ownership) = match mod_kind {
- ModKind::Loaded(_, inline, _) => {
- // Inline `mod foo { ... }`, but we still need to push directories.
- let (dir_path, dir_ownership) = mod_dir_path(
- &self.cx.sess,
- ident,
- &attrs,
- &self.cx.current_expansion.module,
- self.cx.current_expansion.dir_ownership,
- *inline,
- );
- item.attrs = attrs;
- (None, dir_path, dir_ownership)
- }
- ModKind::Unloaded => {
- // We have an outline `mod foo;` so we need to parse the file.
- let old_attrs_len = attrs.len();
- let ParsedExternalMod {
- mut items,
- inner_span,
- file_path,
- dir_path,
- dir_ownership,
- } = parse_external_mod(
- &self.cx.sess,
- ident,
- span,
- &self.cx.current_expansion.module,
- self.cx.current_expansion.dir_ownership,
- &mut attrs,
- );
-
- if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
- (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
- }
-
- *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
- item.attrs = attrs;
- if item.attrs.len() > old_attrs_len {
- // If we loaded an out-of-line module and added some inner attributes,
- // then we need to re-configure it and re-collect attributes for
- // resolution and expansion.
- item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(
- attr,
- Annotatable::Item(item),
- AstFragmentKind::Items,
- )
- .make_items();
- }
- }
- (Some(file_path), dir_path, dir_ownership)
- }
- };
-
- // Set the module info before we flat map.
- let mut module = self.cx.current_expansion.module.with_dir_path(dir_path);
- module.mod_path.push(ident);
- if let Some(file_path) = file_path {
- module.file_path_stack.push(file_path);
- }
-
- let orig_module =
- mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
- let orig_dir_ownership =
- mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
-
- let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
-
- // Restore the module info.
- self.cx.current_expansion.dir_ownership = orig_dir_ownership;
- self.cx.current_expansion.module = orig_module;
-
- result
- }
- _ => {
- item.attrs = attrs;
- // The crate root is special - don't assign an ID to it.
- if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) {
- assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
- } else {
- noop_flat_map_item(item, self)
- }
- }
- }
+ self.flat_map_node(node)
}
- fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
- .make_trait_items();
- }
-
- match item.kind {
- ast::AssocItemKind::MacCall(ref mac) => {
- self.check_attributes(&item.attrs, &mac);
- item.and_then(|item| match item.kind {
- ast::AssocItemKind::MacCall(mac) => {
- self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
- }
- }
+ fn visit_crate(&mut self, node: &mut ast::Crate) {
+ self.visit_node(node)
}
- fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
- let mut item = configure!(self, item);
-
- if let Some(attr) = self.take_first_attr(&mut item) {
- return self
- .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
- .make_impl_items();
- }
-
- match item.kind {
- ast::AssocItemKind::MacCall(ref mac) => {
- self.check_attributes(&item.attrs, &mac);
- item.and_then(|item| match item.kind {
- ast::AssocItemKind::MacCall(mac) => {
- self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
- }
- }
+ fn visit_ty(&mut self, node: &mut P<ast::Ty>) {
+ self.visit_node(node)
}
- fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
- match ty.kind {
- ast::TyKind::MacCall(_) => {}
- _ => return noop_visit_ty(ty, self),
- };
-
- visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
- ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(),
- _ => unreachable!(),
- });
+ fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
+ self.visit_node(node)
}
- fn flat_map_foreign_item(
- &mut self,
- foreign_item: P<ast::ForeignItem>,
- ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
- let mut foreign_item = configure!(self, foreign_item);
-
- if let Some(attr) = self.take_first_attr(&mut foreign_item) {
- return self
- .collect_attr(
- attr,
- Annotatable::ForeignItem(foreign_item),
- AstFragmentKind::ForeignItems,
- )
- .make_foreign_items();
- }
-
- match foreign_item.kind {
- ast::ForeignItemKind::MacCall(ref mac) => {
- self.check_attributes(&foreign_item.attrs, &mac);
- foreign_item.and_then(|item| match item.kind {
- ast::ForeignItemKind::MacCall(mac) => {
- self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items()
- }
- _ => unreachable!(),
- })
- }
- _ => {
- assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
- foreign_item,
- self
- ))
- }
- }
+ fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
+ self.cfg.configure_expr(node);
+ self.visit_node(node)
}
- fn flat_map_generic_param(
- &mut self,
- param: ast::GenericParam,
- ) -> SmallVec<[ast::GenericParam; 1]> {
- let mut param = configure!(self, param);
-
- if let Some(attr) = self.take_first_attr(&mut param) {
- return self
- .collect_attr(
- attr,
- Annotatable::GenericParam(param),
- AstFragmentKind::GenericParams,
- )
- .make_generic_params();
- }
+ fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
+ self.flat_map_node(AstLikeWrapper::new(node, OptExprTag))
+ }
- assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
+ fn visit_block(&mut self, node: &mut P<ast::Block>) {
+ let orig_dir_ownership = mem::replace(
+ &mut self.cx.current_expansion.dir_ownership,
+ DirOwnership::UnownedViaBlock,
+ );
+ noop_visit_block(node, self);
+ self.cx.current_expansion.dir_ownership = orig_dir_ownership;
}
- fn visit_id(&mut self, id: &mut ast::NodeId) {
+ fn visit_id(&mut self, id: &mut NodeId) {
// We may have already assigned a `NodeId`
// by calling `assign_id`
if self.monotonic && *id == ast::DUMMY_NODE_ID {
+#![feature(associated_type_bounds)]
+#![feature(associated_type_defaults)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![cfg_attr(bootstrap, feature(destructuring_assignment))]
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,
span,
is_placeholder: true,
}]),
- AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
+ AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
attrs: Default::default(),
id,
ident,
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,
for ch in data.as_str().chars() {
escaped.extend(ch.escape_debug());
}
- let stream = vec![
+ let stream = [
Ident(sym::doc, false),
Eq,
TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
let integer = TokenKind::lit(token::Integer, symbol, suffix);
let a = tokenstream::TokenTree::token(minus, span);
let b = tokenstream::TokenTree::token(integer, span);
- return vec![a, b].into_iter().collect();
+ return [a, b].into_iter().collect();
}
TokenTree::Literal(self::Literal {
lit: token::Lit { kind: token::Float, symbol, suffix },
let float = TokenKind::lit(token::Float, symbol, suffix);
let a = tokenstream::TokenTree::token(minus, span);
let b = tokenstream::TokenTree::token(float, span);
- return vec![a, b].into_iter().collect();
+ return [a, b].into_iter().collect();
}
TokenTree::Literal(self::Literal { lit, span }) => {
return tokenstream::TokenTree::token(Literal(lit), span).into();
match self {
UnlabelledNodes(len) => vec![None; len],
AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
- SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
+ SomeNodesLabelled(lbls) => lbls,
}
}
#[derive(Debug, HashStable_Generic)]
pub struct PathSegment<'hir> {
/// The identifier portion of this path segment.
- #[stable_hasher(project(name))]
pub ident: Ident,
// `id` and `res` are optional. We currently only use these in save-analysis,
// any path segments without these will not have save-analysis info and
#[stable_hasher(ignore)]
pub hir_id: HirId,
/// The identifier for the field.
- #[stable_hasher(project(name))]
pub ident: Ident,
/// The pattern the field is destructured to.
pub pat: &'hir Pat<'hir>,
#[derive(Debug, HashStable_Generic)]
pub struct TypeBinding<'hir> {
pub hir_id: HirId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub gen_args: &'hir GenericArgs<'hir>,
pub kind: TypeBindingKind<'hir>,
#[derive(Debug, HashStable_Generic)]
pub struct Variant<'hir> {
/// Name of the variant.
- #[stable_hasher(project(name))]
pub ident: Ident,
/// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`).
pub id: HirId,
#[derive(Debug, HashStable_Generic)]
pub struct FieldDef<'hir> {
pub span: Span,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub vis: Visibility<'hir>,
pub hir_id: HirId,
#[derive(Encodable, Debug, HashStable_Generic)]
pub struct TraitItemRef {
pub id: TraitItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
#[derive(Debug, HashStable_Generic)]
pub struct ImplItemRef {
pub id: ImplItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
#[derive(Debug, HashStable_Generic)]
pub struct ForeignItemRef {
pub id: ForeignItemId,
- #[stable_hasher(project(name))]
pub ident: Ident,
pub span: Span,
}
/// Extracts the first `lang = "$name"` out of a list of attributes.
/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
/// are also extracted out when found.
-///
-/// About the `check_name` argument: passing in a `Session` would be simpler,
-/// because then we could call `Session::check_name` directly. But we want to
-/// avoid the need for `rustc_hir` to depend on `rustc_session`, so we
-/// use a closure instead.
-pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
-where
- F: Fn(&'a ast::Attribute, Symbol) -> bool,
-{
+pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| {
Some(match attr {
- _ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
- _ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
- _ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
+ _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
+ _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
+ _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
})
})
map
});
-/// The `check_name` argument avoids the need for `rustc_hir` to depend on
-/// `rustc_session`.
-pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
-where
- F: Fn(&'a ast::Attribute, Symbol) -> bool
+pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
{
- lang_items::extract(check_name, attrs).and_then(|(name, _)| {
+ lang_items::extract(attrs).and_then(|(name, _)| {
$(if name == sym::$name {
Some(sym::$sym)
} else)* {
.keys()
.cloned()
.collect::<FxHashSet<PathBuf>>(),
- vec![PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
+ [PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
.into_iter()
.collect::<FxHashSet<PathBuf>>()
);
// Find newest
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-svh"),
PathBuf::from("crate-dir/s-2234-0000-svh"),
PathBuf::from("crate-dir/s-1234-0000-svh")
// Filter out "-working"
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-working"),
PathBuf::from("crate-dir/s-2234-0000-svh"),
PathBuf::from("crate-dir/s-1234-0000-svh")
);
// Handle empty
- assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited), None);
+ assert_eq!(find_source_directory_in_iter([].into_iter(), &already_visited), None);
// Handle only working
assert_eq!(
find_source_directory_in_iter(
- vec![
+ [
PathBuf::from("crate-dir/s-3234-0000-working"),
PathBuf::from("crate-dir/s-2234-0000-working"),
PathBuf::from("crate-dir/s-1234-0000-working")
self.suggest_boxing_for_return_impl_trait(
err,
ret_sp,
- vec![then, else_sp].into_iter(),
+ [then, else_sp].into_iter(),
);
}
}
);
let sugg = arm_spans
.flat_map(|sp| {
- vec![
- (sp.shrink_to_lo(), "Box::new(".to_string()),
- (sp.shrink_to_hi(), ")".to_string()),
- ]
- .into_iter()
+ [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
+ .into_iter()
})
.collect::<Vec<_>>();
err.multipart_suggestion(
.fields
.iter()
.filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
- .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
+ .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
.find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
{
if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
// error[E0284]: type annotations needed
// --> file.rs:2:5
// |
- // 2 | vec![Ok(2)].into_iter().collect()?;
- // | ^^^^^^^ cannot infer type
+ // 2 | [Ok(2)].into_iter().collect()?;
+ // | ^^^^^^^ cannot infer type
// |
// = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
if span.contains(*call_span) { *call_span } else { span }
/// Useful for other parts of the compiler / Clippy.
pub use builtin::SoftLints;
-pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
+pub use context::{CheckLintNameResult, FindLintError, LintStore};
+pub use context::{EarlyContext, LateContext, LintContext};
pub use early::check_ast_crate;
pub use late::check_crate;
pub use passes::{EarlyLintPass, LateLintPass};
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::lang_items;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::mir::{self, Body, Promoted};
&mut self,
meta: T::Meta,
) -> Result<Lazy<T>, <Self as Decoder>::Error> {
- let min_size = T::min_size(meta);
let distance = self.read_usize()?;
let position = match self.lazy_state {
LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
- assert!(distance + min_size <= start);
- start - distance - min_size
+ assert!(distance <= start);
+ start - distance
}
- LazyState::Previous(last_min_end) => last_min_end.get() + distance,
+ LazyState::Previous(last_pos) => last_pos.get() + distance,
};
- self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
+ self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
}
let ctor_did = data.ctor.map(|index| self.local_def_id(index));
ty::VariantDef::new(
- self.item_ident(index, sess),
+ self.item_ident(index, sess).name,
variant_did,
ctor_did,
data.discr,
.decode(self)
.map(|index| ty::FieldDef {
did: self.local_def_id(index),
- ident: self.item_ident(index, sess),
+ name: self.item_ident(index, sess).name,
vis: self.get_visibility(index),
})
.collect(),
self.get_impl_data(id).constness
}
+ fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
+ self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+ }
+
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
self.get_impl_data(id).coerce_unsized_info
}
}
}
- /// Iterates over each child of the given item.
- fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
+ /// Iterates over all named children of the given module,
+ /// including both proper items and reexports.
+ /// Module here is understood in name resolution sense - it can be a `mod` item,
+ /// or a crate root, or an enum, or a trait.
+ fn for_each_module_child(
+ &self,
+ id: DefIndex,
+ mut callback: impl FnMut(ModChild),
+ sess: &Session,
+ ) {
if let Some(data) = &self.root.proc_macro_data {
- /* If we are loading as a proc macro, we want to return the view of this crate
- * as a proc macro crate.
- */
+ // If we are loading as a proc macro, we want to return
+ // the view of this crate as a proc macro crate.
if id == CRATE_DEF_INDEX {
- let macros = data.macros.decode(self);
- for def_index in macros {
+ for def_index in data.macros.decode(self) {
let raw_macro = self.raw_proc_macro(def_index);
let res = Res::Def(
DefKind::Macro(macro_kind(raw_macro)),
self.local_def_id(def_index),
);
let ident = self.item_ident(def_index, sess);
- callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span });
+ callback(ModChild {
+ ident,
+ res,
+ vis: ty::Visibility::Public,
+ span: ident.span,
+ });
}
}
return;
}
- // Find the item.
- let kind = match self.maybe_kind(id) {
- None => return,
- Some(kind) => kind,
- };
-
// Iterate over all children.
if let Some(children) = self.root.tables.children.get(self, id) {
for child_index in children.decode((self, sess)) {
let vis = self.get_visibility(child_index);
let span = self.get_span(child_index, sess);
- callback(Export { ident, res, vis, span });
+ callback(ModChild { ident, res, vis, span });
// For non-re-export structs and variants add their constructors to children.
// Re-export lists automatically contain constructors when necessary.
let ctor_res =
Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let vis = self.get_visibility(ctor_def_id.index);
- callback(Export { res: ctor_res, vis, ident, span });
+ callback(ModChild { ident, res: ctor_res, vis, span });
}
}
DefKind::Variant => {
vis = ty::Visibility::Restricted(crate_def_id);
}
}
- callback(Export { res: ctor_res, ident, vis, span });
+ callback(ModChild { ident, res: ctor_res, vis, span });
}
_ => {}
}
}
}
- if let EntryKind::Mod(exports) = kind {
- for exp in exports.decode((self, sess)) {
- callback(exp);
+ match self.kind(id) {
+ EntryKind::Mod(exports) => {
+ for exp in exports.decode((self, sess)) {
+ callback(exp);
+ }
}
+ EntryKind::Enum(..) | EntryKind::Trait(..) => {}
+ _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)),
}
}
}
}
+ fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
+ if let Some(children) = self.root.tables.children.get(self, id) {
+ tcx.arena.alloc_from_iter(
+ children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
+ )
+ } else {
+ &[]
+ }
+ }
+
fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
let def_key = self.def_key(id);
let parent = self.local_def_id(def_key.parent.unwrap());
vis: self.get_visibility(id),
defaultness: container.defaultness(),
def_id: self.local_def_id(id),
+ trait_item_def_id: self.get_trait_item_def_id(id),
container: container.with_def_id(parent),
fn_has_self_parameter: has_self,
}
use rustc_ast as ast;
use rustc_data_structures::stable_map::FxHashMap;
-use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
-use rustc_middle::hir::exports::Export;
+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};
tcx.calculate_dtor(def_id, |_,_| Ok(()))
}
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
- associated_item_def_ids => {
- let mut result = SmallVec::<[_; 8]>::new();
- cdata.each_child_of_item(def_id.index,
- |child| result.push(child.res.def_id()), tcx.sess);
- tcx.arena.alloc_slice(&result)
- }
+ associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) }
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
impl_polarity => { cdata.get_impl_polarity(def_id.index) }
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) }
let r = *cdata.dep_kind.lock();
r
}
- item_children => {
+ module_children => {
let mut result = SmallVec::<[_; 8]>::new();
- cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
+ cdata.for_each_module_child(def_id.index, |child| result.push(child), tcx.sess);
tcx.arena.alloc_slice(&result)
}
defined_lib_features => { cdata.get_lib_features(tcx) }
bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
}
- let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
- if !export.vis.is_public() {
+ let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
+ if !child.vis.is_public() {
return;
}
- if let Some(child) = export.res.opt_def_id() {
- if export.ident.name == kw::Underscore {
- fallback_map.insert(child, parent);
+ if let Some(def_id) = child.res.opt_def_id() {
+ if child.ident.name == kw::Underscore {
+ fallback_map.insert(def_id, parent);
return;
}
- match visible_parent_map.entry(child) {
+ match visible_parent_map.entry(def_id) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
- if child.is_local() && entry.get().is_local() {
+ if def_id.is_local() && entry.get().is_local() {
entry.insert(parent);
}
}
Entry::Vacant(entry) => {
entry.insert(parent);
- bfs_queue.push_back(child);
+ if matches!(
+ child.res,
+ Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _)
+ ) {
+ bfs_queue.push_back(def_id);
+ }
}
}
}
};
while let Some(def) = bfs_queue.pop_front() {
- for child in tcx.item_children(def).iter() {
+ for child in tcx.module_children(def).iter() {
add_child(bfs_queue, child, def);
}
}
visible_parent_map.entry(child).or_insert(parent);
}
- visible_parent_map
+ Lrc::new(visible_parent_map)
},
dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
self.get_crate_data(def.krate).get_visibility(def.index)
}
- pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
+ pub fn module_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ModChild> {
let mut result = vec![];
- self.get_crate_data(def_id.krate).each_child_of_item(
+ self.get_crate_data(def_id.krate).for_each_module_child(
def_id.index,
|child| result.push(child),
sess,
) -> 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 {
&mut self,
lazy: Lazy<T>,
) -> Result<(), <Self as Encoder>::Error> {
- let min_end = lazy.position.get() + T::min_size(lazy.meta);
+ let pos = lazy.position.get();
let distance = match self.lazy_state {
LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
LazyState::NodeStart(start) => {
let start = start.get();
- assert!(min_end <= start);
- start - min_end
+ assert!(pos <= start);
+ start - pos
}
- LazyState::Previous(last_min_end) => {
+ LazyState::Previous(last_pos) => {
assert!(
- last_min_end <= lazy.position,
+ last_pos <= lazy.position,
"make sure that the calls to `lazy*` \
are in the same order as the metadata fields",
);
- lazy.position.get() - last_min_end.get()
+ lazy.position.get() - last_pos.get()
}
};
- self.lazy_state = LazyState::Previous(NonZeroUsize::new(min_end).unwrap());
+ self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
self.emit_usize(distance)
}
let meta = value.encode_contents_for_lazy(self);
self.lazy_state = LazyState::NoNode;
- assert!(pos.get() + <T>::min_size(meta) <= self.position());
+ assert!(pos.get() <= self.position());
Lazy::from_position_and_meta(pos, meta)
}
assert!(f.did.is_local());
f.did.index
}));
- self.encode_ident_span(def_id, variant.ident);
+ self.encode_ident_span(def_id, variant.ident(tcx));
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
// FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
// code uses it). However, we skip encoding anything relating to child
// items - we encode information about proc-macros later on.
let reexports = if !self.is_proc_macro {
- match tcx.module_exports(local_def_id) {
+ match tcx.module_reexports(local_def_id) {
Some(exports) => self.lazy(exports),
_ => Lazy::empty(),
}
record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
if self.is_proc_macro {
- record!(self.tables.children[def_id] <- &[]);
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
debug!("EncodeContext::encode_field({:?})", def_id);
record!(self.tables.kind[def_id] <- EntryKind::Field);
- self.encode_ident_span(def_id, field.ident);
+ self.encode_ident_span(def_id, field.ident(self.tcx));
self.encode_item_type(def_id);
}
}
self.encode_ident_span(def_id, impl_item.ident);
self.encode_item_type(def_id);
+ if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
+ record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+ }
if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
}
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_middle::mir;
use rustc_middle::thir;
/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
trait LazyMeta {
type Meta: Copy + 'static;
-
- /// Returns the minimum encoded size.
- // FIXME(eddyb) Give better estimates for certain types.
- fn min_size(meta: Self::Meta) -> usize;
}
impl<T> LazyMeta for T {
type Meta = ();
-
- fn min_size(_: ()) -> usize {
- assert_ne!(std::mem::size_of::<T>(), 0);
- 1
- }
}
impl<T> LazyMeta for [T] {
type Meta = usize;
-
- fn min_size(len: usize) -> usize {
- len * T::min_size(())
- }
}
/// A value of type T referred to by its absolute position
NodeStart(NonZeroUsize),
/// Inside a metadata node, with a previous `Lazy`.
- /// The position is a conservative estimate of where that
- /// previous `Lazy` would end (see their comments).
+ /// The position is where that previous `Lazy` would start.
Previous(NonZeroUsize),
}
ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
+ trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
variances: Table<DefIndex, Lazy<[ty::Variance]>>,
generics: Table<DefIndex, Lazy<ty::Generics>>,
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<[Export]>),
+ Mod(Lazy<[ModChild]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
Option<T>: FixedSizeEncoding,
{
type Meta = usize;
-
- fn min_size(len: usize) -> usize {
- len
- }
}
impl<I: Idx, T> Lazy<Table<I, T>>
+++ /dev/null
-use crate::ty;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::Res;
-use rustc_hir::def_id::LocalDefId;
-use rustc_macros::HashStable;
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-use std::fmt::Debug;
-
-/// This is the replacement export map. It maps a module to all of the exports
-/// within.
-pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
-
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Export {
- /// The name of the target.
- pub ident: Ident,
- /// The resolution of the target.
- /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
- pub res: Res<!>,
- /// The span of the target.
- pub span: Span,
- /// The visibility of the export.
- /// We include non-`pub` exports for hygienic macros that get used from extern crates.
- pub vis: ty::Visibility,
-}
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-pub mod exports;
pub mod map;
pub mod place;
pub mod hir;
pub mod infer;
pub mod lint;
+pub mod metadata;
pub mod middle;
pub mod mir;
pub mod thir;
--- /dev/null
+use crate::ty;
+
+use rustc_hir::def::Res;
+use rustc_macros::HashStable;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates
+/// during name resolution. Right now the bindings are not recreated entirely precisely so we may
+/// need to add more data in the future to correctly support macros 2.0, for example.
+/// Module child can be either a proper item or a reexport (including private imports).
+/// In case of reexport all the fields describe the reexport item itself, not what it refers to.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ModChild {
+ /// Name of the item.
+ pub ident: Ident,
+ /// Resolution result corresponding to the item.
+ /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+ pub res: Res<!>,
+ /// Visibility of the item.
+ pub vis: ty::Visibility,
+ /// Span of the item.
+ pub span: Span,
+}
}
/// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct AccessLevels<Id = LocalDefId> {
pub map: FxHashMap<Id, AccessLevel>,
}
CtorKind::Fictive => {
let mut struct_fmt = fmt.debug_struct(&name);
for (field, place) in iter::zip(&variant_def.fields, places) {
- struct_fmt.field(field.ident.as_str(), place);
+ struct_fmt.field(field.name.as_str(), place);
}
struct_fmt.finish()
}
field: Field,
) -> Self {
self.projs.push(ProjectionElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
+ Some(adt_def.variants[variant_index].name),
variant_index,
));
self.projs.push(ProjectionElem::Field(field, ()));
desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
}
+ /// Maps from associated items on a trait to the corresponding associated
+ /// item on the impl specified by `impl_id`.
+ ///
+ /// For example, with the following code
+ ///
+ /// ```
+ /// struct Type {}
+ /// // DefId
+ /// trait Trait { // trait_id
+ /// fn f(); // trait_f
+ /// fn g() {} // trait_g
+ /// }
+ ///
+ /// impl Trait for Type { // impl_id
+ /// fn f() {} // impl_f
+ /// fn g() {} // impl_g
+ /// }
+ /// ```
+ ///
+ /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
+ ///`{ trait_f: impl_f, trait_g: impl_g }`
+ query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+ storage(ArenaCacheSelector<'tcx>)
+ }
+
/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { "traits in scope at a block" }
}
- query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> {
- desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
+ desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
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) }
}
desc { "fetching what a crate is named" }
separate_provide_extern
}
- query item_children(def_id: DefId) -> &'tcx [Export] {
- desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+ query module_children(def_id: DefId) -> &'tcx [ModChild] {
+ desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
desc { "calculating the missing lang items in a crate" }
separate_provide_extern
}
- query visible_parent_map(_: ()) -> DefIdMap<DefId> {
- storage(ArenaCacheSelector<'tcx>)
+ query visible_parent_map(_: ()) -> Lrc<DefIdMap<DefId>> {
desc { "calculating the visible parent map" }
}
query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
};
if let Some(variant) = variant {
- write!(f, "{}", variant.ident)?;
+ write!(f, "{}", variant.name)?;
// Only for Adt we can have `S {...}`,
// which we handle separately here.
if let PatKind::Wild = *p.pattern.kind {
continue;
}
- let name = variant.fields[p.field.index()].ident;
+ let name = variant.fields[p.field.index()].name;
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
printed += 1;
}
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_span::symbol::Ident;
/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
Trait(DefId),
}
-impl<'tcx> Node {
+impl Node {
pub fn is_from_trait(&self) -> bool {
matches!(self, Node::Trait(..))
}
- /// Iterate over the items defined directly by the given (impl or trait) node.
- pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> {
- tcx.associated_items(self.def_id()).in_definition_order()
- }
-
- /// Finds an associated item defined in this node.
+ /// Trys to find the associated item that implements `trait_item_def_id`
+ /// defined in this node.
///
/// If this returns `None`, the item can potentially still be found in
/// parents of this node.
- pub fn item(
+ pub fn item<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
- trait_item_name: Ident,
- trait_item_kind: ty::AssocKind,
- trait_def_id: DefId,
- ) -> Option<ty::AssocItem> {
- tcx.associated_items(self.def_id())
- .filter_by_name_unhygienic(trait_item_name.name)
- .find(move |impl_item| {
- trait_item_kind == impl_item.kind
- && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
- })
- .copied()
+ trait_item_def_id: DefId,
+ ) -> Option<&'tcx ty::AssocItem> {
+ match *self {
+ Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
+ Node::Impl(impl_def_id) => {
+ let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
+ Some(tcx.associated_item(*id))
+ }
+ }
}
pub fn def_id(&self) -> DefId {
impl<'tcx> Ancestors<'tcx> {
/// Finds the bottom-most (ie. most specialized) definition of an associated
/// item.
- pub fn leaf_def(
- mut self,
- tcx: TyCtxt<'tcx>,
- trait_item_name: Ident,
- trait_item_kind: ty::AssocKind,
- ) -> Option<LeafDef> {
- let trait_def_id = self.trait_def_id;
+ pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> {
let mut finalizing_node = None;
self.find_map(|node| {
- if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
+ if let Some(item) = node.item(tcx, trait_item_def_id) {
if finalizing_node.is_none() {
let is_specializable = item.defaultness.is_default()
|| tcx.impl_defaultness(node.def_id()).is_default();
}
}
- Some(LeafDef { item, defining_node: node, finalizing_node })
+ Some(LeafDef { item: *item, defining_node: node, finalizing_node })
} else {
// Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
finalizing_node = Some(node);
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
- static CACHE: RefCell<FxHashMap<usize, Fingerprint>> = Default::default();
+ static CACHE: RefCell<FxHashMap<(usize, HashingControls), Fingerprint>> = Default::default();
}
let hash: Fingerprint = CACHE.with(|cache| {
let addr = self as *const AdtDef as usize;
- *cache.borrow_mut().entry(addr).or_insert_with(|| {
+ let hashing_controls = hcx.hashing_controls();
+ *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
let ty::AdtDef { did, ref variants, ref flags, ref repr } = *self;
let mut hasher = StableHasher::new();
}
}
+/// Information about an associated item
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
pub defaultness: hir::Defaultness,
pub container: AssocItemContainer,
+ /// If this is an item in an impl of a trait then this is the `DefId` of
+ /// the associated item on the trait that this implements.
+ pub trait_item_def_id: Option<DefId>,
+
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,
write!(
&mut symbol,
"__{}",
- def.variants[variant].fields[idx as usize].ident.name.as_str(),
+ def.variants[variant].fields[idx as usize].name.as_str(),
)
.unwrap();
}
curr_string = format!(
"{}.{}",
curr_string,
- def.variants[variant].fields[idx as usize].ident.name.as_str()
+ def.variants[variant].fields[idx as usize].name.as_str()
);
}
ty::Tuple(_) => {
) -> Place<'tcx> {
self.mk_place_elem(
place,
- PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
+ PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index),
)
}
providers.in_scope_traits_map =
|tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map);
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
- providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]);
+ providers.module_reexports =
+ |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
tcx.crate_name
use crate::ty;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_query_system::ich::StableHashingContext;
use std::cell::RefCell;
{
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
- static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
+ static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> =
RefCell::new(Default::default());
}
let hash = CACHE.with(|cache| {
- let key = (self.as_ptr() as usize, self.len());
+ let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
if let Some(&hash) = cache.borrow().get(&key) {
return hash;
}
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
let adt_kind = adt_def.adt_kind();
let adt_packed = adt_def.repr.pack.is_some();
- let build_variant_info = |n: Option<Ident>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
+ let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
let mut min_size = Size::ZERO;
let field_info: Vec<_> = flds
.iter()
if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
debug!(
"print-type-size `{:#?}` variant {}",
- layout, adt_def.variants[index].ident
+ layout, adt_def.variants[index].name
);
let variant_def = &adt_def.variants[index];
- let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect();
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
record(
adt_kind.into(),
adt_packed,
None,
- vec![build_variant_info(Some(variant_def.ident), &fields, layout)],
+ vec![build_variant_info(Some(variant_def.name), &fields, layout)],
);
} else {
// (This case arises for *empty* enums; so give it
.variants
.iter_enumerated()
.map(|(i, variant_def)| {
- let fields: Vec<_> =
- variant_def.fields.iter().map(|f| f.ident.name).collect();
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
build_variant_info(
- Some(variant_def.ident),
+ Some(variant_def.name),
&fields,
layout.for_variant(self, i),
)
pub use generics::*;
pub use vtable::*;
-use crate::hir::exports::ExportMap;
+use crate::metadata::ModChild;
+use crate::middle::privacy::AccessLevels;
use crate::mir::{Body, GeneratorLayout};
use crate::traits::{self, Reveal};
use crate::ty;
pub definitions: rustc_hir::definitions::Definitions,
pub cstore: Box<CrateStoreDyn>,
pub visibilities: FxHashMap<LocalDefId, Visibility>,
+ pub access_levels: AccessLevels,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
- pub export_map: ExportMap,
+ pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Extern prelude entries. The value is `true` if the entry was introduced
/// via `extern crate` item and not `--extern` option or compiler built-in.
/// If this variant is a struct variant, then this is `None`.
pub ctor_def_id: Option<DefId>,
/// Variant or struct name.
- #[stable_hasher(project(name))]
- pub ident: Ident,
+ pub name: Symbol,
/// Discriminant of this variant.
pub discr: VariantDiscr,
/// Fields of this variant.
/// If someone speeds up attribute loading to not be a performance concern, they can
/// remove this hack and use the constructor `DefId` everywhere.
pub fn new(
- ident: Ident,
+ name: Symbol,
variant_did: Option<DefId>,
ctor_def_id: Option<DefId>,
discr: VariantDiscr,
is_field_list_non_exhaustive: bool,
) -> Self {
debug!(
- "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
+ "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
- ident, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+ name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
VariantDef {
def_id: variant_did.unwrap_or(parent_did),
ctor_def_id,
- ident,
+ name,
discr,
fields,
ctor_kind,
pub fn is_recovered(&self) -> bool {
self.flags.intersects(VariantFlags::IS_RECOVERED)
}
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
pub struct FieldDef {
pub did: DefId,
- #[stable_hasher(project(name))]
- pub ident: Ident,
+ pub name: Symbol,
pub vis: Visibility,
}
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).subst(tcx, subst)
}
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
+ }
}
pub type Attributes<'tcx> = &'tcx [ast::Attribute];
}
pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
- variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id))
+ variant
+ .fields
+ .iter()
+ .position(|field| self.hygienic_eq(ident, field.ident(self), variant.def_id))
}
/// Returns `true` if the impls are the same polarity and the trait either
// that's public and whose identifier isn't `_`.
let reexport = self
.tcx()
- .item_children(visible_parent)
+ .module_children(visible_parent)
.iter()
.filter(|child| child.res.opt_def_id() == Some(def_id))
.find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
if !first {
p!(", ");
}
- p!(write("{}: ", field_def.ident), print(field));
+ p!(write("{}: ", field_def.name), print(field));
first = false;
}
p!(" }}");
// Iterate external crate defs but be mindful about visibility
while let Some(def) = queue.pop() {
- for child in tcx.item_children(def).iter() {
+ for child in tcx.module_children(def).iter() {
if !child.vis.is_public() {
continue;
}
collect_fn(&child.ident, ns, def_id);
}
- if seen_defs.insert(def_id) {
+ if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
+ && seen_defs.insert(def_id)
+ {
queue.push(def_id);
}
}
use crate::dep_graph;
-use crate::hir::exports::Export;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintLevelMap;
+use crate::metadata::ModChild;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use crate::middle::lib_features::LibFeatures;
}
/// Returns the type of metadata for (potentially fat) pointers to this type.
- pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
- // FIXME: should this normalize?
- let tail = tcx.struct_tail_without_normalization(self);
+ pub fn ptr_metadata_ty(
+ &'tcx self,
+ tcx: TyCtxt<'tcx>,
+ normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ ) -> Ty<'tcx> {
+ let tail = tcx.struct_tail_with_normalize(self, normalize);
match tail.kind() {
// Sized types
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
pub fn struct_tail_with_normalize(
self,
mut ty: Ty<'tcx>,
- normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>,
+ mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> {
let recursion_limit = self.recursion_limit();
for iteration in 0.. {
}
crate fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Self {
- self.project(PlaceElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
- variant_index,
- ))
+ self.project(PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index))
}
fn index(self, index: Local) -> Self {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let elem = ProjectionElem::Downcast(
- Some(adt_def.variants[variant_index].ident.name),
- variant_index,
- );
+ let elem =
+ ProjectionElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index);
let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
if let ty::Adt(edef, _) = pat_ty.kind() {
if edef.is_enum()
&& edef.variants.iter().any(|variant| {
- variant.ident == ident && variant.ctor_kind == CtorKind::Const
+ variant.ident(cx.tcx) == ident && variant.ctor_kind == CtorKind::Const
})
{
let variant_count = edef.variants.len();
continue;
}
}
- let sp = def.variants[*variant_index].ident.span;
+ let sp = def.variants[*variant_index].ident(cx.tcx).span;
if covered.contains(&sp) {
// Don't point at variants that have already been covered due to other patterns to avoid
// visual clutter.
};
if let Some(variant) = variant {
- write!(f, "{}", variant.ident)?;
+ write!(f, "{}", variant.name)?;
}
// Without `cx`, we can't know which field corresponds to which, so we can't
if let Some(variant_path) = subpath {
let base_place = tcx.mk_place_elem(
self.place,
- ProjectionElem::Downcast(Some(variant.ident.name), variant_index),
+ ProjectionElem::Downcast(Some(variant.name), variant_index),
);
let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs);
values.push(discr.val);
saved_locals: &GeneratorSavedLocals,
) {
let did = body.source.def_id();
- let allowed_upvars = tcx.erase_regions(upvars);
+ let param_env = tcx.param_env(did);
+
+ let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars);
let allowed = match witness.kind() {
- &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s),
+ &ty::GeneratorWitness(interior_tys) => {
+ tcx.normalize_erasing_late_bound_regions(param_env, interior_tys)
+ }
_ => {
tcx.sess.delay_span_bug(
body.span,
}
};
- let param_env = tcx.param_env(did);
-
for (local, decl) in body.local_decls.iter_enumerated() {
// Ignore locals which are internal or not saved between yields.
if !saved_locals.contains(local) || decl.internal {
if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
- let overridden_methods: FxHashSet<_> =
- impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
+ let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
for method in tcx.provided_trait_methods(trait_ref.def_id) {
- if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
+ if overridden_methods.contains_key(&method.def_id) {
continue;
}
/// a diagnostic to suggest removing them.
///
/// ```ignore (diagnostic)
- /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
- /// ^^ help: remove extra angle brackets
+ /// let _ = [1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ /// ^^ help: remove extra angle brackets
/// ```
///
/// If `true` is returned, then trailing brackets were recovered, tokens were consumed
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
{
if let ty::AssocItem {
- kind: ty::AssocKind::Fn, ident, defaultness, ..
- } = trait_item
+ kind: ty::AssocKind::Fn,
+ defaultness,
+ def_id: trait_item_id,
+ ..
+ } = *trait_item
{
// we can ignore functions that do not have default bodies:
// if those are unimplemented it will be catched by typeck.
if !defaultness.has_value()
|| self
.tcx
- .has_attr(trait_item.def_id, sym::default_method_body_is_const)
+ .has_attr(trait_item_id, sym::default_method_body_is_const)
{
continue;
}
let is_implemented = ancestors
- .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
+ .leaf_def(self.tcx, trait_item_id)
.map(|node_item| !node_item.defining_node.is_from_trait())
.unwrap_or(false);
if !is_implemented {
- to_implement.push(ident.to_string());
+ to_implement.push(self.tcx.item_name(trait_item_id).to_string());
}
}
}
use crate::check_attr::target_from_impl_item;
use crate::weak_lang_items;
-use rustc_ast::Attribute;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id);
- let check_name = |attr: &Attribute, sym| attr.has_name(sym);
- if let Some((value, span)) = extract(check_name, &attrs) {
+ if let Some((value, span)) = extract(&attrs) {
match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
}
}
- if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
- for impl_item_ref in items {
- let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
- let trait_item_def_id = self
- .tcx
- .associated_items(trait_did)
- .filter_by_name_unhygienic(impl_item.ident.name)
- .next()
- .map(|item| item.def_id);
- if let Some(def_id) = trait_item_def_id {
- // Pass `None` to skip deprecation warnings.
- self.tcx.check_stability(def_id, None, impl_item.span, None);
- }
+ for impl_item_ref in items {
+ let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+
+ if let Some(def_id) = impl_item.trait_item_def_id {
+ // Pass `None` to skip deprecation warnings.
+ self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
}
}
}
//! Validity checking for weak lang items
-use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
- let check_name = |attr: &Attribute, sym| attr.has_name(sym);
let attrs = self.tcx.hir().attrs(i.hir_id());
- if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) {
+ if let Some((lang_item, _)) = lang_items::extract(attrs) {
self.register(lang_item, i.span);
}
intravisit::walk_foreign_item(self, i)
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
use rustc_middle::bug;
use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
self.access_levels.map.get(&def_id).copied()
}
+ fn update_with_hir_id(
+ &mut self,
+ hir_id: hir::HirId,
+ level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ let def_id = self.tcx.hir().local_def_id(hir_id);
+ self.update(def_id, level)
+ }
+
/// Updates node level and returns the updated level.
fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
let old_level = self.get(def_id);
let vis = self.tcx.visibility(item_id.def_id);
self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
}
- if let Some(exports) = self.tcx.module_exports(module_def_id) {
+ if let Some(exports) = self.tcx.module_reexports(module_def_id) {
for export in exports {
if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
if let Res::Def(def_kind, def_id) = export.res {
| DefKind::Generator => (),
}
}
-
- /// Given the path segments of an `ItemKind::Use`, then we need
- /// to update the visibility of the intermediate use so that it isn't linted
- /// by `unreachable_pub`.
- ///
- /// This isn't trivial as `path.res` has the `DefId` of the eventual target
- /// of the use statement not of the next intermediate use statement.
- ///
- /// To do this, consider the last two segments of the path to our intermediate
- /// use statement. We expect the penultimate segment to be a module and the
- /// last segment to be the name of the item we are exporting. We can then
- /// look at the items contained in the module for the use statement with that
- /// name and update that item's visibility.
- ///
- /// FIXME: This solution won't work with glob imports and doesn't respect
- /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
- fn update_visibility_of_intermediate_use_statements(
- &mut self,
- segments: &[hir::PathSegment<'_>],
- ) {
- if let [.., module, segment] = segments {
- if let Some(item) = module
- .res
- .and_then(|res| res.mod_def_id())
- // If the module is `self`, i.e. the current crate,
- // there will be no corresponding item.
- .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
- .and_then(|def_id| def_id.as_local())
- .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
- {
- if let hir::ItemKind::Mod(m) = &item.kind {
- for &item_id in m.item_ids {
- let item = self.tcx.hir().item(item_id);
- if !self.tcx.hygienic_eq(
- segment.ident,
- item.ident,
- item_id.def_id.to_def_id(),
- ) {
- continue;
- }
- if let hir::ItemKind::Use(..) = item.kind {
- self.update(item.def_id, Some(AccessLevel::Exported));
- }
- }
- }
- }
- }
- }
}
impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let inherited_item_level = match item.kind {
+ let item_level = match item.kind {
hir::ItemKind::Impl { .. } => {
- Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
- }
- // Only exported `macro_rules!` items are public, but they always are.
- hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => {
- let def_id = item.def_id.to_def_id();
- let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export);
- if is_macro_export { Some(AccessLevel::Public) } else { None }
- }
- // Foreign modules inherit level from parents.
- hir::ItemKind::ForeignMod { .. } => self.prev_level,
- // Other `pub` items inherit levels from parents.
- hir::ItemKind::Const(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::ExternCrate(..)
- | hir::ItemKind::GlobalAsm(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::Macro(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::Static(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Trait(..)
- | hir::ItemKind::TraitAlias(..)
- | hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Union(..)
- | hir::ItemKind::Use(..) => {
- if item.vis.node.is_pub() {
- self.prev_level
- } else {
- None
- }
+ let impl_level =
+ Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels);
+ self.update(item.def_id, impl_level)
}
+ _ => self.get(item.def_id),
};
- // Update level of the item itself.
- let item_level = self.update(item.def_id, inherited_item_level);
-
- // Update levels of nested things.
- match item.kind {
- hir::ItemKind::Enum(ref def, _) => {
- for variant in def.variants {
- let variant_level =
- self.update(self.tcx.hir().local_def_id(variant.id), item_level);
- if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
- }
- for field in variant.data.fields() {
- self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
- }
- }
- }
- hir::ItemKind::Impl(ref impl_) => {
- for impl_item_ref in impl_.items {
- if impl_.of_trait.is_some()
- || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
- {
- self.update(impl_item_ref.id.def_id, item_level);
- }
- }
- }
- hir::ItemKind::Trait(.., trait_item_refs) => {
- for trait_item_ref in trait_item_refs {
- self.update(trait_item_ref.id.def_id, item_level);
- }
- }
- hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
- if let Some(ctor_hir_id) = def.ctor_hir_id() {
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
- }
- for field in def.fields() {
- if field.vis.node.is_pub() {
- self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
- }
- }
- }
- hir::ItemKind::Macro(ref macro_def) => {
- self.update_reachability_from_macro(item.def_id, macro_def);
- }
- hir::ItemKind::ForeignMod { items, .. } => {
- for foreign_item in items {
- if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
- self.update(foreign_item.id.def_id, item_level);
- }
- }
- }
-
- hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::Use(..)
- | hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::GlobalAsm(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::TraitAlias(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::ExternCrate(..) => {}
- }
-
// Mark all items in interfaces of reachable items as reachable.
match item.kind {
// The interface is empty.
- hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
+ hir::ItemKind::ExternCrate(..) => {}
// All nested items are checked by `visit_item`.
hir::ItemKind::Mod(..) => {}
- // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
- // all of the items of a mod in `visit_mod` looking for use statements, we handle
- // making sure that intermediate use statements have their visibilities updated here.
- hir::ItemKind::Use(path, _) => {
- if item_level.is_some() {
- self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
- }
- }
+ hir::ItemKind::Use(..) => {}
// The interface is empty.
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::OpaqueTy(..) => {
}
// Visit everything except for private impl items.
hir::ItemKind::Impl(ref impl_) => {
+ for impl_item_ref in impl_.items {
+ if impl_.of_trait.is_some()
+ || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+ {
+ self.update(impl_item_ref.id.def_id, item_level);
+ }
+ }
+
if item_level.is_some() {
self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
}
}
}
-
// Visit everything, but enum variants have their own levels.
hir::ItemKind::Enum(ref def, _) => {
if item_level.is_some() {
self.reach(item.def_id, item_level).generics().predicates();
}
+
+ let enum_level = self.get(item.def_id);
for variant in def.variants {
- let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
+ let variant_level = self.update_with_hir_id(variant.id, enum_level);
+
if variant_level.is_some() {
+ if let Some(ctor_id) = variant.data.ctor_hir_id() {
+ self.update_with_hir_id(ctor_id, variant_level);
+ }
+
for field in variant.data.fields() {
self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level)
.ty();
}
}
}
+ hir::ItemKind::Macro(ref macro_def) => {
+ self.update_reachability_from_macro(item.def_id, macro_def);
+ }
// Visit everything, but foreign items have their own levels.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
intravisit::walk_block(self, b);
self.prev_level = orig_level;
}
-
- fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
- // This code is here instead of in visit_item so that the
- // crate module gets processed as well.
- if self.prev_level.is_some() {
- let def_id = self.tcx.hir().local_def_id(id);
- if let Some(exports) = self.tcx.module_exports(def_id) {
- for export in exports.iter() {
- if export.vis.is_public() {
- if let Some(def_id) = export.res.opt_def_id() {
- if let Some(def_id) = def_id.as_local() {
- self.update(def_id, Some(AccessLevel::Exported));
- }
- }
- }
- }
- }
- }
-
- intravisit::walk_mod(self, m, id);
- }
}
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, hir_id).1;
if !field.vis.is_accessible_from(def_id, self.tcx) {
let label = if in_update_syntax {
- format!("field `{}` is private", field.ident)
+ format!("field `{}` is private", field.name)
} else {
"private field".to_string()
};
span,
E0451,
"field `{}` of {} `{}` is private",
- field.ident,
+ field.name,
def.variant_descr(),
self.tcx.def_path_str(def.did)
)
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx,
- access_levels: Default::default(),
+ access_levels: tcx.resolutions(()).access_levels.clone(),
macro_reachable: Default::default(),
prev_level: Some(AccessLevel::Public),
changed: false,
};
+
loop {
tcx.hir().walk_toplevel_module(&mut visitor);
if visitor.changed {
break;
}
}
- visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
tcx.arena.alloc(visitor.access_levels)
}
K::with_deps(None, op)
}
+ /// Used to wrap the deserialization of a query result from disk,
+ /// This method enforces that no new `DepNodes` are created during
+ /// query result deserialization.
+ ///
+ /// Enforcing this makes the query dep graph simpler - all nodes
+ /// must be created during the query execution, and should be
+ /// created from inside the 'body' of a query (the implementation
+ /// provided by a particular compiler crate).
+ ///
+ /// Consider the case of three queries `A`, `B`, and `C`, where
+ /// `A` invokes `B` and `B` invokes `C`:
+ ///
+ /// `A -> B -> C`
+ ///
+ /// Suppose that decoding the result of query `B` required re-computing
+ /// the query `C`. If we did not create a fresh `TaskDeps` when
+ /// decoding `B`, we would still be using the `TaskDeps` for query `A`
+ /// (if we needed to re-execute `A`). This would cause us to create
+ /// a new edge `A -> C`. If this edge did not previously
+ /// exist in the `DepGraph`, then we could end up with a different
+ /// `DepGraph` at the end of compilation, even if there were no
+ /// meaningful changes to the overall program (e.g. a newline was added).
+ /// In addition, this edge might cause a subsequent compilation run
+ /// to try to force `C` before marking other necessary nodes green. If
+ /// `C` did not exist in the new compilation session, then we could
+ /// get an ICE. Normally, we would have tried (and failed) to mark
+ /// some other query green (e.g. `item_children`) which was used
+ /// to obtain `C`, which would prevent us from ever trying to force
+ /// a non-existent `D`.
+ ///
+ /// It might be possible to enforce that all `DepNode`s read during
+ /// deserialization already exist in the previous `DepGraph`. In
+ /// the above example, we would invoke `D` during the deserialization
+ /// of `B`. Since we correctly create a new `TaskDeps` from the decoding
+ /// of `B`, this would result in an edge `B -> D`. If that edge already
+ /// existed (with the same `DepPathHash`es), then it should be correct
+ /// to allow the invocation of the query to proceed during deserialization
+ /// of a query result. We would merely assert that the dep-graph fragment
+ /// that would have been added by invoking `C` while decoding `B`
+ /// is equivalent to the dep-graph fragment that we already instantiated for B
+ /// (at the point where we successfully marked B as green).
+ ///
+ /// However, this would require additional complexity
+ /// in the query infrastructure, and is not currently needed by the
+ /// decoding of any query results. Should the need arise in the future,
+ /// we should consider extending the query system with this functionality.
+ pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
+ where
+ OP: FnOnce() -> R,
+ {
+ let mut deps = TaskDeps::default();
+ deps.read_allowed = false;
+ let deps = Lock::new(deps);
+ K::with_deps(Some(&deps), op)
+ }
+
/// Starts a new dep-graph task. Dep-graph tasks are specified
/// using a free function (`task`) and **not** a closure -- this
/// is intentional because we want to exercise tight control over
reads: SmallVec::new(),
read_set: Default::default(),
phantom_data: PhantomData,
+ read_allowed: true,
}))
};
let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
if let Some(task_deps) = task_deps {
let mut task_deps = task_deps.lock();
let task_deps = &mut *task_deps;
+
+ if !task_deps.read_allowed {
+ panic!("Illegal read of: {:?}", dep_node_index);
+ }
+
if cfg!(debug_assertions) {
data.current.total_read_count.fetch_add(1, Relaxed);
}
reads: EdgesVec,
read_set: FxHashSet<DepNodeIndex>,
phantom_data: PhantomData<DepNode<K>>,
+ /// Whether or not we allow `DepGraph::read_index` to run.
+ /// This is normally true, except inside `with_query_deserialization`,
+ /// where it set to `false` to enforce that no new `DepNode` edges are
+ /// created. See the documentation of `with_query_deserialization` for
+ /// more details.
+ read_allowed: bool,
}
impl<K> Default for TaskDeps<K> {
reads: EdgesVec::new(),
read_set: FxHashSet::default(),
phantom_data: PhantomData,
+ read_allowed: true,
}
}
}
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashingControls, NodeIdHashingMode};
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
pub struct StableHashingContext<'a> {
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
+ // The value of `-Z incremental-ignore-spans`.
+ // This field should only be used by `debug_opts_incremental_ignore_span`
+ incremental_ignore_spans: bool,
pub(super) body_resolver: BodyResolver<'a>,
- hash_spans: bool,
- pub(super) node_id_hashing_mode: NodeIdHashingMode,
-
// Very often, we are hashing something that does not need the
// `CachingSourceMapView`, so we initialize it lazily.
raw_source_map: &'a SourceMap,
caching_source_map: Option<CachingSourceMapView<'a>>,
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub enum NodeIdHashingMode {
- Ignore,
- HashDefPath,
+ pub(super) hashing_controls: HashingControls,
}
/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
body_resolver: BodyResolver::Forbidden,
definitions,
cstore,
+ incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
caching_source_map: None,
raw_source_map: sess.source_map(),
- hash_spans: hash_spans_initial,
- node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+ hashing_controls: HashingControls {
+ hash_spans: hash_spans_initial,
+ node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+ },
}
}
#[inline]
pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
- let prev_hash_spans = self.hash_spans;
- self.hash_spans = hash_spans;
+ let prev_hash_spans = self.hashing_controls.hash_spans;
+ self.hashing_controls.hash_spans = hash_spans;
f(self);
- self.hash_spans = prev_hash_spans;
+ self.hashing_controls.hash_spans = prev_hash_spans;
}
#[inline]
mode: NodeIdHashingMode,
f: F,
) {
- let prev = self.node_id_hashing_mode;
- self.node_id_hashing_mode = mode;
+ let prev = self.hashing_controls.node_id_hashing_mode;
+ self.hashing_controls.node_id_hashing_mode = mode;
f(self);
- self.node_id_hashing_mode = prev;
+ self.hashing_controls.node_id_hashing_mode = prev;
}
#[inline]
}
IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
}
+
+ #[inline]
+ pub fn hashing_controls(&self) -> HashingControls {
+ self.hashing_controls.clone()
+ }
}
impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
#[inline]
fn hash_spans(&self) -> bool {
- self.hash_spans
+ self.hashing_controls.hash_spans
+ }
+
+ #[inline]
+ fn debug_opts_incremental_ignore_spans(&self) -> bool {
+ self.incremental_ignore_spans
}
#[inline]
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
self.source_map().span_data_to_lines_and_cols(span)
}
+
+ #[inline]
+ fn hashing_controls(&self) -> HashingControls {
+ self.hashing_controls.clone()
+ }
}
impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
#[inline]
fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
let hcx = self;
- match hcx.node_id_hashing_mode {
+ match hcx.hashing_controls.node_id_hashing_mode {
NodeIdHashingMode::Ignore => {
// Don't do anything.
}
#[inline]
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
- let prev_hash_node_ids = self.node_id_hashing_mode;
- self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+ let prev_hash_node_ids = self.hashing_controls.node_id_hashing_mode;
+ self.hashing_controls.node_id_hashing_mode = NodeIdHashingMode::Ignore;
f(self);
- self.node_id_hashing_mode = prev_hash_node_ids;
+ self.hashing_controls.node_id_hashing_mode = prev_hash_node_ids;
}
#[inline]
//! ICH - Incremental Compilation Hash
-pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
+pub use self::hcx::StableHashingContext;
+pub use rustc_data_structures::stable_hasher::NodeIdHashingMode;
use rustc_span::symbol::{sym, Symbol};
mod hcx;
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
};
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
-
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHasher};
#[cfg(parallel_compiler)]
// Some things are never cached on disk.
if query.cache_on_disk {
let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
- let result = query.try_load_from_disk(tcx, prev_dep_node_index);
+
+ // The call to `with_query_deserialization` enforces that no new `DepNodes`
+ // are created during deserialization. See the docs of that method for more
+ // details.
+ let result = dep_graph
+ .with_query_deserialization(|| query.try_load_from_disk(tcx, prev_dep_node_index));
+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
--- /dev/null
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_ast::ForeignMod;
+use rustc_ast::NodeId;
+use rustc_ast_lowering::ResolverAstLowering;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::ty::Visibility;
+use rustc_span::sym;
+
+use crate::imports::ImportKind;
+use crate::BindingKey;
+use crate::NameBinding;
+use crate::NameBindingKind;
+use crate::Resolver;
+
+pub struct AccessLevelsVisitor<'r, 'a> {
+ r: &'r mut Resolver<'a>,
+ prev_level: Option<AccessLevel>,
+ changed: bool,
+}
+
+impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
+ /// Fills the `Resolver::access_levels` table with public & exported items
+ /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+ /// need access to a TyCtxt for that.
+ pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+ let mut visitor =
+ AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
+
+ visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
+ visitor.set_exports_access_level(CRATE_DEF_ID);
+
+ while visitor.changed {
+ visitor.reset();
+ visit::walk_crate(&mut visitor, krate);
+ }
+
+ tracing::info!("resolve::access_levels: {:#?}", r.access_levels);
+ }
+
+ fn reset(&mut self) {
+ self.changed = false;
+ self.prev_level = Some(AccessLevel::Public);
+ }
+
+ /// Update the access level of the exports of the given module accordingly. The module access
+ /// level has to be Exported or Public.
+ /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
+ fn set_exports_access_level(&mut self, module_id: LocalDefId) {
+ assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+
+ // Set the given binding access level to `AccessLevel::Public` and
+ // sets the rest of the `use` chain to `AccessLevel::Exported` until
+ // we hit the actual exported item.
+ let set_import_binding_access_level =
+ |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level| {
+ while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+ binding.kind
+ {
+ this.set_access_level(import.id, access_level);
+ if let ImportKind::Single { additional_ids, .. } = import.kind {
+ this.set_access_level(additional_ids.0, access_level);
+ this.set_access_level(additional_ids.1, access_level);
+ }
+
+ access_level = Some(AccessLevel::Exported);
+ binding = nested_binding;
+ }
+ };
+
+ let module_level = self.r.access_levels.map.get(&module_id).copied();
+ assert!(module_level >= Some(AccessLevel::Exported));
+
+ if let Some(exports) = self.r.reexport_map.get(&module_id) {
+ let pub_exports = exports
+ .iter()
+ .filter(|ex| ex.vis == Visibility::Public)
+ .cloned()
+ .collect::<Vec<_>>();
+
+ let module = self.r.get_module(module_id.to_def_id()).unwrap();
+ for export in pub_exports.into_iter() {
+ if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
+ self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
+ }
+
+ if let Some(ns) = export.res.ns() {
+ let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
+ let name_res = self.r.resolution(module, key);
+ if let Some(binding) = name_res.borrow().binding() {
+ set_import_binding_access_level(self, binding, module_level)
+ }
+ }
+ }
+ }
+ }
+
+ /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
+ /// This function will panic if the `NodeId` does not have a `LocalDefId`
+ fn set_access_level(
+ &mut self,
+ node_id: NodeId,
+ access_level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
+ }
+
+ fn set_access_level_def_id(
+ &mut self,
+ def_id: LocalDefId,
+ access_level: Option<AccessLevel>,
+ ) -> Option<AccessLevel> {
+ let old_level = self.r.access_levels.map.get(&def_id).copied();
+ if old_level < access_level {
+ self.r.access_levels.map.insert(def_id, access_level.unwrap());
+ self.changed = true;
+ access_level
+ } else {
+ old_level
+ }
+ }
+}
+
+impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ let inherited_item_level = match item.kind {
+ // Resolved in rustc_privacy when types are available
+ ast::ItemKind::Impl(..) => return,
+
+ // Only exported `macro_rules!` items are public, but they always are
+ ast::ItemKind::MacroDef(..) => {
+ let is_macro_export =
+ item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
+ if is_macro_export { Some(AccessLevel::Public) } else { None }
+ }
+
+ // Foreign modules inherit level from parents.
+ ast::ItemKind::ForeignMod(..) => self.prev_level,
+
+ // Other `pub` items inherit levels from parents.
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::Fn(..)
+ | ast::ItemKind::Mod(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::Enum(..)
+ | ast::ItemKind::Struct(..)
+ | ast::ItemKind::Union(..)
+ | ast::ItemKind::Trait(..)
+ | ast::ItemKind::TraitAlias(..) => {
+ if item.vis.kind.is_pub() {
+ self.prev_level
+ } else {
+ None
+ }
+ }
+
+ // Should be unreachable at this stage
+ ast::ItemKind::MacCall(..) => panic!(
+ "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+ ),
+ };
+
+ let access_level = self.set_access_level(item.id, inherited_item_level);
+
+ // Set access level of nested items.
+ // If it's a mod, also make the visitor walk all of its items
+ match item.kind {
+ ast::ItemKind::Mod(..) => {
+ if access_level.is_some() {
+ self.set_exports_access_level(self.r.local_def_id(item.id));
+ }
+
+ let orig_level = std::mem::replace(&mut self.prev_level, access_level);
+ visit::walk_item(self, item);
+ self.prev_level = orig_level;
+ }
+
+ ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
+ for nested in items {
+ if nested.vis.kind.is_pub() {
+ self.set_access_level(nested.id, access_level);
+ }
+ }
+ }
+ ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+ for variant in variants {
+ let variant_level = self.set_access_level(variant.id, access_level);
+ if let Some(ctor_id) = variant.data.ctor_id() {
+ self.set_access_level(ctor_id, access_level);
+ }
+
+ for field in variant.data.fields() {
+ self.set_access_level(field.id, variant_level);
+ }
+ }
+ }
+ ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+ if let Some(ctor_id) = def.ctor_id() {
+ self.set_access_level(ctor_id, access_level);
+ }
+
+ for field in def.fields() {
+ if field.vis.kind.is_pub() {
+ self.set_access_level(field.id, access_level);
+ }
+ }
+ }
+ ast::ItemKind::Trait(ref trait_kind) => {
+ for nested in trait_kind.items.iter() {
+ self.set_access_level(nested.id, access_level);
+ }
+ }
+
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::TraitAlias(..)
+ | ast::ItemKind::MacroDef(..)
+ | ast::ItemKind::Fn(..) => return,
+
+ // Unreachable kinds
+ ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
+ }
+ }
+}
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_metadata::creader::LoadedMacro;
use rustc_middle::bug;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::ty;
use rustc_session::cstore::CrateStore;
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
}
crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
- for child in self.cstore().item_children_untracked(module.def_id(), self.session) {
+ for child in self.cstore().module_children_untracked(module.def_id(), self.session) {
let parent_scope = ParentScope::module(module, self);
BuildReducedGraphVisitor { r: self, parent_scope }
.build_reduced_graph_for_external_crate_res(child);
used: Cell::new(false),
});
- debug!("add_import({:?})", import);
-
self.r.indeterminate_imports.push(import);
match import.kind {
// Don't add unresolved underscore imports to modules
prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
};
match use_tree.kind {
- ast::UseTreeKind::Simple(rename, ..) => {
+ ast::UseTreeKind::Simple(rename, id1, id2) => {
let mut ident = use_tree.ident();
let mut module_path = prefix;
let mut source = module_path.pop().unwrap();
},
type_ns_only,
nested,
+ additional_ids: (id1, id2),
};
+
self.add_import(
module_path,
kind,
}
/// Builds the reduced graph for a single item in an external crate.
- fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
+ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
let parent = self.parent_scope.module;
- let Export { ident, res, vis, span } = child;
+ let ModChild { ident, res, vis, span } = child;
let res = res.expect_non_local();
let expansion = self.parent_scope.expansion;
// Record primary definitions.
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_hir::def::{self, PartialRes};
use rustc_hir::def_id::DefId;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
use rustc_middle::span_bug;
use rustc_middle::ty;
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
+ /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
+ /// (eg. implicit struct constructors)
+ additional_ids: (NodeId, NodeId),
},
Glob {
is_prelude: bool,
import.span,
);
import.vis.set(orig_vis);
-
source_bindings[ns].set(binding);
} else {
return;
if is_good_import || binding.is_macro_def() {
let res = binding.res().expect_non_local();
if res != def::Res::Err {
- reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
+ reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span });
}
}
});
if let Some(def_id) = module.opt_def_id() {
// Call to `expect_local` should be fine because current
// code is only called for local modules.
- self.r.export_map.insert(def_id.expect_local(), reexports);
+ self.r.reexport_map.insert(def_id.expect_local(), reexports);
}
}
}
}
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,
};
use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
-use rustc_middle::hir::exports::ExportMap;
+use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
+use crate::access_levels::AccessLevelsVisitor;
+
type Res = def::Res<NodeId>;
+mod access_levels;
mod build_reduced_graph;
mod check_unused;
mod def_collector;
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- export_map: ExportMap,
+ reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
/// they are declared in the static array generated by proc_macro_harness.
proc_macros: Vec<NodeId>,
confused_type_with_std_module: FxHashMap<Span, Span>,
+
+ access_levels: AccessLevels,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
import_res_map: Default::default(),
label_res_map: Default::default(),
extern_crate_map: Default::default(),
- export_map: FxHashMap::default(),
+ reexport_map: FxHashMap::default(),
trait_map: NodeMap::default(),
underscore_disambiguator: 0,
empty_module,
trait_impls: Default::default(),
proc_macros: Default::default(),
confused_type_with_std_module: Default::default(),
+ access_levels: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
let definitions = self.definitions;
let visibilities = self.visibilities;
let extern_crate_map = self.extern_crate_map;
- let export_map = self.export_map;
+ let reexport_map = self.reexport_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
let glob_map = self.glob_map;
let main_def = self.main_def;
let confused_type_with_std_module = self.confused_type_with_std_module;
+ let access_levels = self.access_levels;
ResolverOutputs {
definitions,
cstore: Box::new(self.crate_loader.into_cstore()),
visibilities,
+ access_levels,
extern_crate_map,
- export_map,
+ reexport_map,
glob_map,
maybe_unused_trait_imports,
maybe_unused_extern_crates,
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
ResolverOutputs {
definitions: self.definitions.clone(),
+ access_levels: self.access_levels.clone(),
cstore: Box::new(self.cstore().clone()),
visibilities: self.visibilities.clone(),
extern_crate_map: self.extern_crate_map.clone(),
- export_map: self.export_map.clone(),
+ reexport_map: self.reexport_map.clone(),
glob_map: self.glob_map.clone(),
maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
pub fn resolve_crate(&mut self, krate: &Crate) {
self.session.time("resolve_crate", || {
self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
+ self.session.time("resolve_access_levels", || {
+ AccessLevelsVisitor::compute_access_levels(self, krate)
+ });
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
self.session.time("resolve_main", || self.resolve_main());
}
Res::Def(HirDefKind::AssocFn, decl_id) => {
let def_id = if decl_id.is_local() {
- let ti = self.tcx.associated_item(decl_id);
-
- self.tcx
- .associated_items(ti.container.id())
- .filter_by_name_unhygienic(ti.ident.name)
- .find(|item| item.defaultness.has_value())
- .map(|item| item.def_id)
+ if self.tcx.associated_item(decl_id).defaultness.has_value() {
+ Some(decl_id)
+ } else {
+ None
+ }
} else {
None
};
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
///
-/// See the discussion in [`DefId`] for more information
-/// on the possibility of hash collisions in rustc,
+/// For more information on the possibility of hash collisions in rustc,
+/// see the discussion in [`DefId`].
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub struct StableCrateId(pub(crate) u64);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
// On below-64 bit systems we can simply use the derived `Hash` impl
#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
-// Note that the order is essential here, see below why
+#[repr(C)]
+// We guarantee field order. Note that the order is essential here, see below why.
pub struct DefId {
+ // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
+ // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl
+ // into a direct call to 'u64::hash(_)`.
+ #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))]
pub index: DefIndex,
pub krate: CrateNum,
+ #[cfg(all(target_pointer_width = "64", target_endian = "big"))]
+ pub index: DefIndex,
}
// On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_data_structures::unhash::UnhashMap;
}
}
+/// Assert that the provided `HashStableContext` is configured with the 'default'
+/// `HashingControls`. We should always have bailed out before getting to here
+/// with a non-default mode. With this check in place, we can avoid the need
+/// to maintain separate versions of `ExpnData` hashes for each permutation
+/// of `HashingControls` settings.
+fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
+ match ctx.hashing_controls() {
+ // Ideally, we would also check that `node_id_hashing_mode` was always
+ // `NodeIdHashingMode::HashDefPath`. However, we currently end up hashing
+ // `Span`s in this mode, and there's not an easy way to change that.
+ // All of the span-related data that we hash is pretty self-contained
+ // (in particular, we don't hash any `HirId`s), so this shouldn't result
+ // in any caching problems.
+ // FIXME: Enforce that we don't end up transitively hashing any `HirId`s,
+ // or ensure that this method is always invoked with the same
+ // `NodeIdHashingMode`
+ //
+ // Note that we require that `hash_spans` be set according to the global
+ // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
+ // which will cause us to require that this method always be called with `Span` hashing
+ // enabled.
+ HashingControls { hash_spans, node_id_hashing_mode: _ }
+ if hash_spans == !ctx.debug_opts_incremental_ignore_spans() => {}
+ other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+ }
+}
+
/// A unique hash value associated to an expansion.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
pub struct ExpnHash(Fingerprint);
"Already set disambiguator for ExpnData: {:?}",
expn_data
);
+ assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
let mut expn_hash = expn_data.hash_expn(&mut ctx);
let disambiguator = HygieneData::with(|data| {
impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ assert_default_hashing_controls(ctx, "ExpnId");
let hash = if *self == ExpnId::root() {
// Avoid fetching TLS storage for a trivial often-used value.
Fingerprint::ZERO
use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
+use rustc_data_structures::stable_hasher::HashingControls;
pub mod def_id;
use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
pub mod lev_distance;
pub trait HashStableContext {
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
fn hash_spans(&self) -> bool;
+ /// Accesses `sess.opts.debugging_opts.incremental_ignore_spans` since
+ /// we don't have easy access to a `Session`
+ fn debug_opts_incremental_ignore_spans(&self) -> bool;
fn def_span(&self, def_id: LocalDefId) -> Span;
fn span_data_to_lines_and_cols(
&mut self,
span: &SpanData,
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
+ fn hashing_controls(&self) -> HashingControls;
}
impl<CTX> HashStable<CTX> for Span
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
item_type.hash_stable(hcx, &mut hasher);
- });
- });
- // If this is a function, we hash the signature as well.
- // This is not *strictly* needed, but it may help in some
- // situations, see the `run-make/a-b-a-linker-guard` test.
- if let ty::FnDef(..) = item_type.kind() {
- item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
- }
+ // If this is a function, we hash the signature as well.
+ // This is not *strictly* needed, but it may help in some
+ // situations, see the `run-make/a-b-a-linker-guard` test.
+ if let ty::FnDef(..) = item_type.kind() {
+ item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
+ }
- // also include any type parameters (for generic items)
- substs.hash_stable(&mut hcx, &mut hasher);
+ // also include any type parameters (for generic items)
+ substs.hash_stable(hcx, &mut hasher);
- if let Some(instantiating_crate) = instantiating_crate {
- tcx.def_path_hash(instantiating_crate.as_def_id())
- .stable_crate_id()
- .hash_stable(&mut hcx, &mut hasher);
- }
+ if let Some(instantiating_crate) = instantiating_crate {
+ tcx.def_path_hash(instantiating_crate.as_def_id())
+ .stable_crate_id()
+ .hash_stable(hcx, &mut hasher);
+ }
- // We want to avoid accidental collision between different types of instances.
- // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
- // instances without this.
- discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
+ // We want to avoid accidental collision between different types of instances.
+ // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+ // instances without this.
+ discriminant(&instance.def).hash_stable(hcx, &mut hasher);
+ });
+ });
});
// 64 bits should be enough to avoid collisions.
linker: Some("avr-gcc".to_owned()),
executables: true,
eh_frame_header: false,
- pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
- .into_iter()
- .collect(),
- late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
+ pre_link_args: [(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
.into_iter()
.collect(),
+ late_link_args: [(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])].into_iter().collect(),
max_atomic_width: Some(0),
atomic_cas: false,
..TargetOptions::default()
fn to_json(&self) -> Json {
Json::Object(match self {
StackProbeType::None => {
- vec![(String::from("kind"), "none".to_json())].into_iter().collect()
+ [(String::from("kind"), "none".to_json())].into_iter().collect()
}
StackProbeType::Inline => {
- vec![(String::from("kind"), "inline".to_json())].into_iter().collect()
+ [(String::from("kind"), "inline".to_json())].into_iter().collect()
}
StackProbeType::Call => {
- vec![(String::from("kind"), "call".to_json())].into_iter().collect()
+ [(String::from("kind"), "call".to_json())].into_iter().collect()
}
- StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![
+ StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
(String::from("kind"), "inline-or-call".to_json()),
(
String::from("min-llvm-version-for-inline"),
spans
.iter()
.flat_map(|&span| {
- vec![
+ [
(span.shrink_to_lo(), "Box<".to_string()),
(span.shrink_to_hi(), ">".to_string()),
]
.returns
.iter()
.flat_map(|expr| {
- vec![
+ [
(expr.span.shrink_to_lo(), "Box::new(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
]
// Any type with multiple potential metadata types is therefore not eligible.
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
- // FIXME: should this normalize?
- let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+ let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
+ normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ )
+ .value
+ });
+
match tail.kind() {
ty::Bool
| ty::Char
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
- | ty::Error(_) => false,
+ | ty::Error(_) => {
+ if tail.has_infer_types() {
+ candidate_set.mark_ambiguous();
+ }
+ false
+ },
}
}
super::ImplSource::Param(..) => {
_: ImplSourcePointeeData,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
-
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
- let substs = tcx.mk_substs([self_ty.into()].iter());
+ let mut obligations = vec![];
+ let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ &mut obligations,
+ )
+ });
+
+ let substs = tcx.mk_substs([self_ty.into()].iter());
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
let predicate = ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
- ty: self_ty.ptr_metadata_ty(tcx),
+ ty: metadata_ty,
};
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+ .with_addl_obligations(obligations)
}
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
assoc_ty_def_id: DefId,
) -> Result<specialization_graph::LeafDef, ErrorReported> {
let tcx = selcx.tcx();
- let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
let trait_def = tcx.trait_def(trait_def_id);
// for the associated item at the given impl.
// If there is no such item in that impl, this function will fail with a
// cycle error if the specialization graph is currently being built.
- let impl_node = specialization_graph::Node::Impl(impl_def_id);
- for item in impl_node.items(tcx) {
- if matches!(item.kind, ty::AssocKind::Type)
- && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
- {
- return Ok(specialization_graph::LeafDef {
- item: *item,
- defining_node: impl_node,
- finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
- });
- }
+ if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) {
+ let item = tcx.associated_item(impl_item_id);
+ let impl_node = specialization_graph::Node::Impl(impl_def_id);
+ return Ok(specialization_graph::LeafDef {
+ item: *item,
+ defining_node: impl_node,
+ finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+ });
}
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
- if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
+ if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) {
Ok(assoc_item)
} else {
// This is saying that neither the trait nor
// could only arise through a compiler bug --
// if the user wrote a bad item name, it
// should have failed in astconv.
- bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id))
+ bug!(
+ "No associated type `{}` for {}",
+ tcx.item_name(assoc_ty_def_id),
+ tcx.def_path_str(impl_def_id)
+ )
}
}
ty::Generator(_, ref substs, _) => {
let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
let witness = substs.as_generator().witness();
- t.rebind(vec![ty].into_iter().chain(iter::once(witness)).collect())
+ t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
ty::GeneratorWitness(types) => {
item: Option<&hir::Item<'tcx>>,
cause: &mut traits::ObligationCause<'tcx>,
pred: &ty::Predicate<'tcx>,
- mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>,
) {
debug!(
"extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
trait_ref, item, cause, pred
);
- let items = match item {
- Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items,
+ let (items, impl_def_id) = match item {
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
_ => return,
};
let fix_span =
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
if let ty::Projection(projection_ty) = proj.ty.kind() {
- let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id);
- if let Some(impl_item_span) =
- items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
+ if let Some(&impl_item_id) =
+ tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
{
- cause.span = impl_item_span;
+ if let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
}
}
}
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() {
- if let Some(impl_item_span) = trait_assoc_items
- .find(|i| i.def_id == item_def_id)
- .and_then(|trait_assoc_item| {
- items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
- })
+ if let Some(&impl_item_id) =
+ tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
{
- cause.span = impl_item_span;
+ if let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
}
}
}
item,
&mut cause,
&obligation.predicate,
- tcx.associated_items(trait_ref.def_id).in_definition_order(),
);
traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
};
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
let def_id = associated_ty_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
- let (impl_id, trait_id) = match assoc_item.container {
- AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
- AssocItemContainer::ImplContainer(def_id) => {
- (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
- }
- };
+ let impl_id = assoc_item.container.id();
match assoc_item.kind {
AssocKind::Type => {}
_ => unimplemented!("Not possible??"),
}
- let trait_item = self
- .interner
- .tcx
- .associated_items(trait_id)
- .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
- .unwrap();
+ let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
let binders = binders_for(self.interner, bound_vars);
let ty = self
Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
impl_id: chalk_ir::ImplId(impl_id),
- associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
+ associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
value: chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::AssociatedTyValueBound { ty },
--- /dev/null
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers {
+ associated_item,
+ associated_item_def_ids,
+ associated_items,
+ impl_item_implementor_ids,
+ trait_of_item,
+ ..*providers
+ };
+}
+
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
+ let item = tcx.hir().expect_item(def_id.expect_local());
+ match item.kind {
+ hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
+ trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+ ),
+ hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
+ impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+ ),
+ hir::ItemKind::TraitAlias(..) => &[],
+ _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
+ }
+}
+
+fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
+ let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+ ty::AssocItems::new(items)
+}
+
+fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ tcx.associated_items(impl_id)
+ .in_definition_order()
+ .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
+ .collect()
+}
+
+/// If the given `DefId` describes an item belonging to a trait,
+/// returns the `DefId` of the trait that the trait item belongs to;
+/// otherwise, returns `None`.
+fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+ tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
+ ty::TraitContainer(def_id) => Some(def_id),
+ ty::ImplContainer(_) => None,
+ })
+}
+
+fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let parent_id = tcx.hir().get_parent_item(id);
+ let parent_def_id = tcx.hir().local_def_id(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_def_id);
+ match parent_item.kind {
+ hir::ItemKind::Impl(ref impl_) => {
+ if let Some(impl_item_ref) =
+ impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ {
+ let assoc_item =
+ associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ hir::ItemKind::Trait(.., ref trait_item_refs) => {
+ if let Some(trait_item_ref) =
+ trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ {
+ let assoc_item =
+ associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+ debug_assert_eq!(assoc_item.def_id, def_id);
+ return assoc_item;
+ }
+ }
+
+ _ => {}
+ }
+
+ span_bug!(
+ parent_item.span,
+ "unexpected parent of trait or impl item or item not found: {:?}",
+ parent_item.kind
+ )
+}
+
+fn associated_item_from_trait_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ trait_item_ref: &hir::TraitItemRef,
+) -> ty::AssocItem {
+ let def_id = trait_item_ref.id.def_id;
+ let (kind, has_self) = match trait_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ ty::AssocItem {
+ ident: trait_item_ref.ident,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: trait_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ trait_item_def_id: Some(def_id.to_def_id()),
+ container: ty::TraitContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
+
+fn associated_item_from_impl_item_ref(
+ tcx: TyCtxt<'_>,
+ parent_def_id: LocalDefId,
+ impl_item_ref: &hir::ImplItemRef,
+) -> ty::AssocItem {
+ let def_id = impl_item_ref.id.def_id;
+ let (kind, has_self) = match impl_item_ref.kind {
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ };
+
+ let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
+
+ ty::AssocItem {
+ ident: impl_item_ref.ident,
+ kind,
+ vis: tcx.visibility(def_id),
+ defaultness: impl_item_ref.defaultness,
+ def_id: def_id.to_def_id(),
+ trait_item_def_id,
+ container: ty::ImplContainer(parent_def_id.to_def_id()),
+ fn_has_self_parameter: has_self,
+ }
+}
+
+fn impl_item_base_id<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ parent_def_id: LocalDefId,
+ impl_item: &hir::ImplItemRef,
+) -> Option<DefId> {
+ let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
+
+ // If the trait reference itself is erroneous (so the compilation is going
+ // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+ // isn't populated for such impls.
+ if impl_trait_ref.references_error() {
+ return None;
+ }
+
+ // Locate trait items
+ let associated_items = tcx.associated_items(impl_trait_ref.def_id);
+
+ // Match item against trait
+ let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
+
+ let mut trait_item = items.next()?;
+
+ let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
+ (ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
+ (ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
+ (ty::AssocKind::Type, hir::AssocItemKind::Type) => true,
+ _ => false,
+ };
+
+ // If we don't have a compatible item, we'll use the first one whose name matches
+ // to report an error.
+ let mut compatible_kind = is_compatible(&trait_item);
+
+ if !compatible_kind {
+ if let Some(ty_trait_item) = items.find(is_compatible) {
+ compatible_kind = true;
+ trait_item = ty_trait_item;
+ }
+ }
+
+ if compatible_kind {
+ Some(trait_item.def_id)
+ } else {
+ report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
+ None
+ }
+}
+
+#[inline(never)]
+#[cold]
+fn report_mismatch_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_item_def_id: DefId,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+ impl_item: &hir::ImplItemRef,
+) {
+ let mut err = match impl_item.kind {
+ hir::AssocItemKind::Const => {
+ // Find associated const definition.
+ struct_span_err!(
+ tcx.sess,
+ impl_item.span,
+ E0323,
+ "item `{}` is an associated const, which doesn't match its trait `{}`",
+ impl_item.ident,
+ impl_trait_ref.print_only_trait_path()
+ )
+ }
+
+ hir::AssocItemKind::Fn { .. } => {
+ struct_span_err!(
+ tcx.sess,
+ impl_item.span,
+ E0324,
+ "item `{}` is an associated method, which doesn't match its trait `{}`",
+ impl_item.ident,
+ impl_trait_ref.print_only_trait_path()
+ )
+ }
+
+ hir::AssocItemKind::Type => {
+ struct_span_err!(
+ tcx.sess,
+ impl_item.span,
+ E0325,
+ "item `{}` is an associated type, which doesn't match its trait `{}`",
+ impl_item.ident,
+ impl_trait_ref.print_only_trait_path()
+ )
+ }
+ };
+
+ err.span_label(impl_item.span, "does not match trait");
+ if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
+ err.span_label(trait_span, "item in trait");
+ }
+ err.emit();
+}
let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
- let item = tcx.associated_item(def.did);
- resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
+ resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs)
} else {
let ty = tcx.type_of(def.def_id_for_type_of());
let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
fn resolve_associated_item<'tcx>(
tcx: TyCtxt<'tcx>,
- trait_item: &ty::AssocItem,
+ trait_item_id: DefId,
param_env: ty::ParamEnv<'tcx>,
trait_id: DefId,
rcvr_substs: SubstsRef<'tcx>,
) -> Result<Option<Instance<'tcx>>, ErrorReported> {
- let def_id = trait_item.def_id;
- debug!(
- "resolve_associated_item(trait_item={:?}, \
- param_env={:?}, \
- trait_id={:?}, \
- rcvr_substs={:?})",
- def_id, param_env, trait_id, rcvr_substs
- );
+ debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item");
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
traits::ImplSource::UserDefined(impl_data) => {
debug!(
"resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
- param_env, trait_item, rcvr_substs, impl_data
+ param_env, trait_item_id, rcvr_substs, impl_data
);
assert!(!rcvr_substs.needs_infer());
assert!(!trait_ref.needs_infer());
let trait_def = tcx.trait_def(trait_def_id);
let leaf_def = trait_def
.ancestors(tcx, impl_data.impl_def_id)?
- .leaf_def(tcx, trait_item.ident, trait_item.kind)
+ .leaf_def(tcx, trait_item_id)
.unwrap_or_else(|| {
- bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+ bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
});
let substs = tcx.infer_ctxt().enter(|infcx| {
// performs (i.e. that the definition's type in the `impl` matches
// the declaration in the `trait`), so that we can cheaply check
// here if it failed, instead of approximating it.
- if trait_item.kind == ty::AssocKind::Const
- && trait_item.def_id != leaf_def.item.def_id
+ if leaf_def.item.kind == ty::AssocKind::Const
+ && trait_item_id != leaf_def.item.def_id
&& leaf_def.item.def_id.is_local()
{
let normalized_type_of = |def_id, substs| {
tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
};
- let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
+ let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
if original_ty != resolved_ty {
let msg = format!(
"Instance::resolve: inconsistent associated `const` type: \
was `{}: {}` but resolved to `{}: {}`",
- tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
+ tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
original_ty,
tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
resolved_ty,
}
traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
- def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
+ def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
substs: rcvr_substs,
}),
_ => None,
},
traits::ImplSource::Object(ref data) => {
- let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
- Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
+ let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
+ Some(Instance {
+ def: ty::InstanceDef::Virtual(trait_item_id, index),
+ substs: rcvr_substs,
+ })
}
traits::ImplSource::Builtin(..) => {
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
// FIXME(eddyb) use lang items for methods instead of names.
- let name = tcx.item_name(def_id);
+ let name = tcx.item_name(trait_item_id);
if name == sym::clone {
let self_ty = trait_ref.self_ty();
};
Some(Instance {
- def: ty::InstanceDef::CloneShim(def_id, self_ty),
+ def: ty::InstanceDef::CloneShim(trait_item_id, self_ty),
substs: rcvr_substs,
})
} else {
// Use the default `fn clone_from` from `trait Clone`.
let substs = tcx.erase_regions(rcvr_substs);
- Some(ty::Instance::new(def_id, substs))
+ Some(ty::Instance::new(trait_item_id, substs))
}
} else {
None
use rustc_middle::ty::query::Providers;
+mod assoc;
mod common_traits;
pub mod instance;
mod needs_drop;
mod ty;
pub fn provide(providers: &mut Providers) {
+ assoc::provide(providers);
common_traits::provide(providers);
needs_drop::provide(providers);
ty::provide(providers);
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_span::{sym, Span};
result
}
-fn associated_item_from_trait_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
- let def_id = trait_item_ref.id.def_id;
- let (kind, has_self) = match trait_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: trait_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: trait_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::TraitContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item_from_impl_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
- let def_id = impl_item_ref.id.def_id;
- let (kind, has_self) = match impl_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
- };
-
- ty::AssocItem {
- ident: impl_item_ref.ident,
- kind,
- vis: tcx.visibility(def_id),
- defaultness: impl_item_ref.defaultness,
- def_id: def_id.to_def_id(),
- container: ty::ImplContainer(parent_def_id.to_def_id()),
- fn_has_self_parameter: has_self,
- }
-}
-
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let parent_id = tcx.hir().get_parent_item(id);
- let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_def_id);
- match parent_item.kind {
- hir::ItemKind::Impl(ref impl_) => {
- if let Some(impl_item_ref) =
- impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
- {
- let assoc_item =
- associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- hir::ItemKind::Trait(.., ref trait_item_refs) => {
- if let Some(trait_item_ref) =
- trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
- {
- let assoc_item =
- associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
- debug_assert_eq!(assoc_item.def_id, def_id);
- return assoc_item;
- }
- }
-
- _ => {}
- }
-
- span_bug!(
- parent_item.span,
- "unexpected parent of trait or impl item or item not found: {:?}",
- parent_item.kind
- )
-}
-
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
ty::AdtSizedConstraint(result)
}
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let item = tcx.hir().expect_item(def_id.expect_local());
- match item.kind {
- hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
- trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
- ),
- hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
- impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
- ),
- hir::ItemKind::TraitAlias(..) => &[],
- _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
- }
-}
-
-fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
- let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
- ty::AssocItems::new(items)
-}
-
fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
tcx.hir()
.get_if_local(def_id)
.map(|ident| ident.span)
}
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
- ty::TraitContainer(def_id) => Some(def_id),
- ty::ImplContainer(_) => None,
- })
-}
-
/// See `ParamEnv` struct definition for details.
#[instrument(level = "debug", skip(tcx))]
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
asyncness,
- associated_item,
- associated_item_def_ids,
- associated_items,
adt_sized_constraint,
def_ident_span,
param_env,
param_env_reveal_all_normalized,
- trait_of_item,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
let variant_def = adt_def
.variants
.iter()
- .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did));
+ .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did));
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
&adt_def
.variants
.iter()
- .map(|variant| variant.ident.name)
+ .map(|variant| variant.name)
.collect::<Vec<Symbol>>(),
assoc_ident.name,
None,
///
/// Without this check the above code is incorrectly accepted: we would ICE if
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
+#[instrument(level = "debug", skip(tcx))]
fn check_opaque_meets_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
- match origin {
- // Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
- // Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {}
- }
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let param_env = tcx.param_env(def_id);
+ let defining_use_anchor = match *origin {
+ hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
+ hir::OpaqueTyOrigin::TyAlias => def_id,
+ };
+ let param_env = tcx.param_env(defining_use_anchor);
- tcx.infer_ctxt().enter(move |infcx| {
+ tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
let inh = Inherited::new(infcx, def_id);
let infcx = &inh.infcx;
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
- match infcx
- .at(&misc_cause, param_env)
- .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs))
- {
+ let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+ trace!(?hidden_type);
+ match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
Err(ty_err) => tcx.sess.delay_span_bug(
- opaque_defn.definition_span,
+ span,
&format!(
- "could not unify `{}` with revealed type:\n{}",
- opaque_defn.concrete_ty, ty_err,
+ "could not check bounds on revealed type `{}`:\n{}",
+ hidden_type, ty_err,
),
),
}
infcx.report_fulfillment_errors(&errors, None, false);
}
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let fcx = FnCtxt::new(&inh, param_env, hir_id);
- fcx.regionck_item(hir_id, span, FxHashSet::default());
+ match origin {
+ // Checked when type checking the function containing them.
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
+ // Can have different predicates to their defining use
+ hir::OpaqueTyOrigin::TyAlias => {
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let fcx = FnCtxt::new(&inh, param_env, hir_id);
+ fcx.regionck_item(hir_id, span, FxHashSet::default());
+ }
+ }
});
}
trait_def: &ty::TraitDef,
trait_item: &ty::AssocItem,
impl_id: DefId,
- impl_item: &hir::ImplItem<'_>,
+ impl_item: &hir::ImplItemRef,
) {
- let kind = match impl_item.kind {
- hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
- hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
- hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
- };
-
let ancestors = match trait_def.ancestors(tcx, impl_id) {
Ok(ancestors) => ancestors,
Err(_) => return,
if parent.is_from_trait() {
None
} else {
- Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+ Some((parent, parent.item(tcx, trait_item.def_id)))
}
});
}
}
-pub(super) fn check_impl_items_against_trait<'tcx>(
+fn check_impl_items_against_trait<'tcx>(
tcx: TyCtxt<'tcx>,
full_impl_span: Span,
impl_id: LocalDefId,
}
}
- // Locate trait definition and items
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
- let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
- let associated_items = tcx.associated_items(impl_trait_ref.def_id);
-
- // Check existing impl methods to see if they are both present in trait
- // and compatible with trait signature
- for impl_item in impl_items {
- let ty_impl_item = tcx.associated_item(impl_item.def_id);
-
- let mut items =
- associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
-
- let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
- let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
- (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
- (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
- (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
- _ => false,
- };
-
- // If we don't have a compatible item, we'll use the first one whose name matches
- // to report an error.
- let mut compatible_kind = is_compatible(&ty_trait_item);
- let mut trait_item = ty_trait_item;
- if !compatible_kind {
- if let Some(ty_trait_item) = items.find(is_compatible) {
- compatible_kind = true;
- trait_item = ty_trait_item;
- }
- }
-
- (compatible_kind, trait_item)
+ for impl_item in impl_item_refs {
+ let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+ let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
+ tcx.associated_item(trait_item_id)
} else {
+ // Checked in `associated_item`.
+ tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
continue;
};
-
- if compatible_kind {
- match impl_item.kind {
- hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- compare_const_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- );
- }
- hir::ImplItemKind::Fn(..) => {
- let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_impl_method(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- }
- hir::ImplItemKind::TyAlias(impl_ty) => {
- let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- compare_ty_impl(
- tcx,
- &ty_impl_item,
- impl_ty.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- }
+ let impl_item_full = tcx.hir().impl_item(impl_item.id);
+ match impl_item_full.kind {
+ hir::ImplItemKind::Const(..) => {
+ // Find associated const definition.
+ compare_const_impl(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ );
+ }
+ hir::ImplItemKind::Fn(..) => {
+ let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+ compare_impl_method(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
+ }
+ hir::ImplItemKind::TyAlias(impl_ty) => {
+ let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+ compare_ty_impl(
+ tcx,
+ &ty_impl_item,
+ impl_ty.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
}
-
- check_specialization_validity(
- tcx,
- trait_def,
- &ty_trait_item,
- impl_id.to_def_id(),
- impl_item,
- );
- } else {
- report_mismatch_error(
- tcx,
- ty_trait_item.def_id,
- impl_trait_ref,
- impl_item,
- &ty_impl_item,
- );
}
+
+ check_specialization_validity(
+ tcx,
+ trait_def,
+ &ty_trait_item,
+ impl_id.to_def_id(),
+ impl_item,
+ );
}
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
- let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
// Check for missing items from trait
let mut missing_items = Vec::new();
- for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+ for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
let is_implemented = ancestors
- .leaf_def(tcx, trait_item.ident, trait_item.kind)
- .map(|node_item| !node_item.defining_node.is_from_trait())
- .unwrap_or(false);
+ .leaf_def(tcx, trait_item_id)
+ .map_or(false, |node_item| node_item.item.defaultness.has_value());
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
- if !trait_item.defaultness.has_value() {
- missing_items.push(*trait_item);
- }
+ missing_items.push(tcx.associated_item(trait_item_id));
}
}
if !missing_items.is_empty() {
+ let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
}
}
}
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_item_def_id: DefId,
- impl_trait_ref: ty::TraitRef<'tcx>,
- impl_item: &hir::ImplItem<'_>,
- ty_impl_item: &ty::AssocItem,
-) {
- let mut err = match impl_item.kind {
- hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0323,
- "item `{}` is an associated const, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
-
- hir::ImplItemKind::Fn(..) => {
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0324,
- "item `{}` is an associated method, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
-
- hir::ImplItemKind::TyAlias(_) => {
- struct_span_err!(
- tcx.sess,
- impl_item.span,
- E0325,
- "item `{}` is an associated type, which doesn't match its trait `{}`",
- ty_impl_item.ident,
- impl_trait_ref.print_only_trait_path()
- )
- }
- };
-
- err.span_label(impl_item.span, "does not match trait");
- if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
- err.span_label(trait_span, "item in trait");
- }
- err.emit();
-}
-
/// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded.
if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
if !stack.contains(&def.did) {
if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
- defs.push((def.did, field.ident.span));
+ defs.push((def.did, field.ident(tcx).span));
return Some(defs);
}
}
],
Applicability::MachineApplicable,
);
- let sugg = vec![sp, cause.span]
+ let sugg = [sp, cause.span]
.into_iter()
.flat_map(|sp| {
- vec![
+ [
(sp.shrink_to_lo(), "Box::new(".to_string()),
(sp.shrink_to_hi(), ")".to_string()),
]
.fields
.iter()
.enumerate()
- .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+ .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
let mut seen_fields = FxHashMap::default();
expr_span,
self.field_ty(base_expr.span, f, base_subs),
);
- let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+ let ident = self
+ .tcx
+ .adjust_ident(f.ident(self.tcx), variant.def_id);
if let Some(_) = remaining_fields.remove(&ident) {
let target_ty =
self.field_ty(base_expr.span, f, substs);
&cause,
target_ty,
fru_ty,
- FieldMisMatch(
- variant.ident.name,
- ident.name,
- ),
+ FieldMisMatch(variant.name, ident.name),
)
.emit(),
}
"{} `{}::{}` has no field named `{}`",
kind_name,
actual,
- variant.ident,
+ variant.name,
field.ident
),
_ => struct_span_err!(
},
ty,
);
+
+ let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
match variant.ctor_kind {
CtorKind::Fn => match ty.kind() {
ty::Adt(adt, ..) if adt.is_enum() => {
err.span_label(
- variant.ident.span,
+ variant_ident_span,
format!(
"`{adt}::{variant}` defined here",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
);
err.span_label(field.ident.span, "field does not exist");
&format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
format!(
"{adt}::{variant}(/* fields */)",
adt = ty,
- variant = variant.ident,
+ variant = variant.name,
),
Applicability::HasPlaceholders,
);
}
_ => {
- err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
+ err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty));
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
if adt.is_enum() {
err.span_label(
field.ident.span,
- format!("`{}::{}` does not have this field", ty, variant.ident),
+ format!("`{}::{}` does not have this field", ty, variant.name),
);
} else {
err.span_label(
.iter()
.filter_map(|field| {
// ignore already set fields and private fields from non-local crates
- if skip.iter().any(|&x| x == field.ident.name)
+ if skip.iter().any(|&x| x == field.name)
|| (!variant.def_id.is_local() && !field.vis.is_public())
{
None
} else {
- Some(field.ident.name)
+ Some(field.name)
}
})
.collect::<Vec<Symbol>>();
.filter(|field| {
let def_scope = self
.tcx
- .adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id)
+ .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
.1;
field.vis.is_accessible_from(def_scope, self.tcx)
})
- .map(|field| field.ident.name)
+ .map(|field| field.name)
.collect()
}
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
let fields = &base_def.non_enum_variant().fields;
- if let Some(index) =
- fields.iter().position(|f| f.ident.normalize_to_macros_2_0() == ident)
+ if let Some(index) = fields
+ .iter()
+ .position(|f| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
let field = &fields[index];
let field_ty = self.field_ty(expr.span, field, substs);
if let ty::Adt(def, _) = output_ty.kind() {
// no field access on enum type
if !def.is_enum() {
- if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) {
+ if def
+ .non_enum_variant()
+ .fields
+ .iter()
+ .any(|field| field.ident(self.tcx) == field_ident)
+ {
add_label = false;
err.span_label(
field_ident.span,
.unwrap()
.fields
.iter()
- .any(|f| f.ident == field)
+ .any(|f| f.ident(self.tcx) == field)
{
if let Some(dot_loc) = expr_snippet.rfind('.') {
found = true;
span, candidate_field, field_path
);
- if candidate_field.ident == target_field {
+ if candidate_field.ident(self.tcx) == target_field {
Some(field_path)
} else if field_path.len() > 3 {
// For compile-time reasons and to avoid infinite recursion we only check for fields
} else {
// recursively search fields of `candidate_field` if it's a ty::Adt
- field_path.push(candidate_field.ident.normalize_to_macros_2_0());
+ field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
let field_ty = candidate_field.ty(self.tcx, subst);
if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
for field in nested_fields.iter() {
- let ident = field.ident.normalize_to_macros_2_0();
+ let ident = field.ident(self.tcx).normalize_to_macros_2_0();
if ident == target_field {
return Some(field_path);
} else {
let variant_def = adt_def
.variants
.iter()
- .find(|vd| tcx.hygienic_eq(method_name, vd.ident, adt_def.did));
+ .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did));
if let Some(variant_def) = variant_def {
// Braced variants generate unusable names in value namespace (reserved for
// possible future use), so variants resolved as associated items may refer to
if unsatisfied_predicates.is_empty() && actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
- &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
+ &adt_def.variants.iter().map(|s| s.name).collect::<Vec<_>>(),
item_name.name,
None,
) {
if Some(*parent_did) != self.tcx.parent(*trait_did)
&& self
.tcx
- .item_children(*parent_did)
+ .module_children(*parent_did)
.iter()
.filter(|child| child.res.opt_def_id() == Some(*trait_did))
.all(|child| child.ident.name == kw::Underscore)
fn report_forbidden_specialization(
tcx: TyCtxt<'_>,
- impl_item: &hir::ImplItem<'_>,
+ impl_item: &hir::ImplItemRef,
parent_impl: DefId,
) {
let mut err = struct_span_err!(
fn missing_items_err(
tcx: TyCtxt<'_>,
impl_span: Span,
- missing_items: &[ty::AssocItem],
+ missing_items: &[&ty::AssocItem],
full_impl_span: Span,
) {
let missing_items_msg = missing_items
let field_def_spans = if fields.is_empty() {
vec![res_span]
} else {
- fields.iter().map(|f| f.ident.span).collect()
+ fields.iter().map(|f| f.ident(self.tcx).span).collect()
};
let last_field_def_span = *field_def_spans.last().unwrap();
.fields
.iter()
.enumerate()
- .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+ .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
.collect::<FxHashMap<_, _>>();
// Keep track of which fields have already appeared in the pattern.
let mut unmentioned_fields = variant
.fields
.iter()
- .map(|field| (field, field.ident.normalize_to_macros_2_0()))
+ .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
.filter(|(_, ident)| !used_fields.contains_key(ident))
.collect::<Vec<_>>();
fields: &[hir::PatField<'_>],
variant: &VariantDef,
) -> String {
- let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::<Vec<Ident>>();
+ let variant_field_idents =
+ variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
fields
.iter()
.map(|field| {
)
.note(&format!(
"extra field `{}` of type `{}` is not allowed",
- field.ident, ty_a,
+ field.name, ty_a,
))
.emit();
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
- field.ident,
+ field.name,
field.ty(tcx, substs_a),
field.ty(tcx, substs_b),
)
diff_fields
.iter()
.map(|&(i, a, b)| {
- format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b)
+ format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
})
.collect::<Vec<_>>()
.join(", ")
use crate::errors;
use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
-use rustc_ast::Attribute;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}
- ty::FieldDef { did: fid.to_def_id(), ident: f.ident, vis: tcx.visibility(fid) }
+ ty::FieldDef { did: fid.to_def_id(), name: f.ident.name, vis: tcx.visibility(fid) }
})
.collect();
let recovered = match def {
_ => false,
};
ty::VariantDef::new(
- ident,
+ ident.name,
variant_did.map(LocalDefId::to_def_id),
ctor_did.map(LocalDefId::to_def_id),
discr,
if tcx.is_weak_lang_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- let check_name = |attr: &Attribute, sym| attr.has_name(sym);
- if let Some(name) = weak_lang_items::link_name(check_name, attrs) {
+ if let Some(name) = weak_lang_items::link_name(attrs) {
codegen_fn_attrs.export_name = Some(name);
codegen_fn_attrs.link_name = Some(name);
}
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id) {
- if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
- if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
- if let Some(trait_item) = tcx
- .associated_items(trait_def_id)
- .filter_by_name_unhygienic(impl_item.ident.name)
- .find(move |trait_item| {
- trait_item.kind == ty::AssocKind::Fn
- && tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
- })
- {
- return tcx
- .codegen_fn_attrs(trait_item.def_id)
- .flags
- .intersects(CodegenFnAttrFlags::TRACK_CALLER);
- }
+ if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container {
+ if let Some(trait_item) = impl_item.trait_item_def_id {
+ return tcx
+ .codegen_fn_attrs(trait_item)
+ .flags
+ .intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
}
}
fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> {
let lang_items = tcx.lang_items();
- let all = vec![
+ let all = [
(lang_items.phantom_data(), vec![ty::Covariant]),
(lang_items.unsafe_cell_type(), vec![ty::Invariant]),
];
description = "The Rust core allocation and collections library"
autotests = false
autobenches = false
-edition = "2018"
+edition = "2021"
[dependencies]
core = { path = "../core" }
use super::search::SearchResult::*;
mod entry;
+
+#[stable(feature = "rust1", since = "1.0.0")]
pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
+
use Entry::*;
/// Minimum number of elements in a node that is not a root.
#[test]
fn test_range_inclusive_max_value() {
let max = usize::MAX;
- let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
+ let map: BTreeMap<_, _> = [(max, 0)].into_iter().collect();
assert_eq!(map.range(max..=max).collect::<Vec<_>>(), &[(&max, &0)]);
}
#[test]
fn test_into_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let vec = [(1, 'a'), (2, 'b'), (3, 'c')];
let map: BTreeMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+ /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
/// buf.reserve_exact(10);
/// assert!(buf.capacity() >= 11);
/// ```
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+ /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
/// buf.reserve(10);
/// assert!(buf.capacity() >= 11);
/// ```
/// ```
/// use std::collections::VecDeque;
///
- /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+ /// let v: VecDeque<_> = [1, 2, 3].into_iter().collect();
/// let range = v.range(2..).copied().collect::<VecDeque<_>>();
/// assert_eq!(range, [3]);
///
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+ /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
/// for v in v.range_mut(2..) {
/// *v *= 2;
/// }
/// ```
/// use std::collections::VecDeque;
///
- /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+ /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
/// let drained = v.drain(2..).collect::<VecDeque<_>>();
/// assert_eq!(drained, [3]);
/// assert_eq!(v, [1, 2]);
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+ /// let mut buf: VecDeque<_> = [1, 2, 3].into_iter().collect();
/// let buf2 = buf.split_off(1);
/// assert_eq!(buf, [1]);
/// assert_eq!(buf2, [2, 3]);
/// ```
/// use std::collections::VecDeque;
///
- /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect();
- /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect();
+ /// let mut buf: VecDeque<_> = [1, 2].into_iter().collect();
+ /// let mut buf2: VecDeque<_> = [3, 4].into_iter().collect();
/// buf.append(&mut buf2);
/// assert_eq!(buf, [1, 2, 3, 4]);
/// assert_eq!(buf2, []);
/// # Examples
///
/// ```
- /// use std::convert::TryInto;
/// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
/// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
/// ```
///
/// If the length doesn't match, the input comes back in `Err`:
/// ```
- /// use std::convert::TryInto;
/// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
/// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
/// ```
/// If you're fine with just getting a prefix of the `Vec<T>`,
/// you can call [`.truncate(N)`](Vec::truncate) first.
/// ```
- /// use std::convert::TryInto;
/// let mut v = String::from("hello world").into_bytes();
/// v.sort();
/// v.truncate(2);
let list: LinkedList<_> = (0..10).collect();
assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
- let list: LinkedList<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
+ let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
}
assert_eq!(a.len(), 4);
assert!(a.iter().eq(&[1, 2, 3, 4]));
- let b: LinkedList<_> = vec![5, 6, 7].into_iter().collect();
+ let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
a.extend(b); // specializes to `append`
assert_eq!(a.len(), 7);
#[test]
fn drain_filter_zst() {
- let mut list: LinkedList<_> = vec![(), (), (), (), ()].into_iter().collect();
+ let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
let initial_len = list.len();
let mut count = 0;
#[test]
fn drain_filter_false() {
- let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
let initial_len = list.len();
let mut count = 0;
#[test]
fn drain_filter_true() {
- let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
let initial_len = list.len();
let mut count = 0;
fn drain_filter_complex() {
{
// [+xxx++++++xxxxx++++x+x++]
- let mut list = vec![
+ let mut list = [
1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
39,
]
{
// [xxx++++++xxxxx++++x+x++]
- let mut list = vec![
- 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
- ]
- .into_iter()
- .collect::<LinkedList<_>>();
+ let mut list =
+ [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
+ .into_iter()
+ .collect::<LinkedList<_>>();
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
assert_eq!(removed.len(), 10);
{
// [xxx++++++xxxxx++++x+x]
let mut list =
- vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
+ [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
.into_iter()
.collect::<LinkedList<_>>();
{
// [xxxxxxxxxx+++++++++++]
- let mut list = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+ let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
.into_iter()
.collect::<LinkedList<_>>();
{
// [+++++++++++xxxxxxxxxx]
- let mut list = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+ let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
.into_iter()
.collect::<LinkedList<_>>();
b.extend(u.chars());
assert_eq!(s, b);
- let c: String = vec![t, u].into_iter().collect();
+ let c: String = [t, u].into_iter().collect();
assert_eq!(s, c);
let mut d = t.to_string();
#[test]
fn test_partition() {
- assert_eq!(vec![].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
- assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
+ assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
}
#[test]
#[test]
fn test_into_iter_count() {
- assert_eq!(vec![1, 2, 3].into_iter().count(), 3);
+ assert_eq!([1, 2, 3].into_iter().count(), 3);
}
#[test]
let v: Vec<i32> = it.collect();
assert_eq!(&v[..], slice);
}
- let mut it = vec![1, 2, 3].into_iter();
+ let mut it = [1, 2, 3].into_iter();
iter_equal(it.clone(), &[1, 2, 3]);
assert_eq!(it.next(), Some(1));
let mut it = it.rev();
#[test]
fn test_into_iter_advance_by() {
- let mut i = vec![1, 2, 3, 4, 5].into_iter();
+ let mut i = [1, 2, 3, 4, 5].into_iter();
i.advance_by(0).unwrap();
i.advance_back_by(0).unwrap();
assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
assert_eq!(*v0, 13);
next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range
assert_eq!(*v0, 13);
- next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact
+ next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact
assert_eq!(*v0, 13);
// spare_capacity_mut
#[test]
fn test_append() {
- let mut a: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
- let mut b: VecDeque<_> = vec![4, 5, 6].into_iter().collect();
+ let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect();
+ let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect();
// normal append
a.append(&mut b);
{
// Same basic idea, but with non-zero len
- let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!");
{
// Same basic idea, but with interesting type size
- let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
}
{
- let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
}
{
- let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+ let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
description = "The Rust Core Library"
autotests = false
autobenches = false
-edition = "2018"
+edition = "2021"
[lib]
test = false
///
/// ```rust
/// #![feature(array_from_fn)]
-/// # // Apparently these doc tests are still on edition2018
-/// # use std::convert::TryInto;
///
/// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
//! Character conversions.
+use crate::char::TryFromCharError;
use crate::convert::TryFrom;
use crate::fmt;
use crate::mem::transmute;
}
}
+/// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing
+/// if the code point is greater than U+00FF.
+///
+/// See [`impl From<u8> for char`](char#impl-From<u8>) for details on the encoding.
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl TryFrom<char> for u8 {
+ type Error = TryFromCharError;
+
+ #[inline]
+ fn try_from(c: char) -> Result<u8, Self::Error> {
+ u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(()))
+ }
+}
+
/// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF.
///
/// Unicode is designed such that this effectively decodes bytes
fmt::Display::fmt(&self.0, f)
}
}
+
+/// The error type returned when a checked char conversion fails.
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct TryFromCharError(pub(crate) ());
+
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl fmt::Display for TryFromCharError {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "unicode code point out of range".fmt(fmt)
+ }
+}
/// ```rust
/// use std::convert::identity;
///
-/// let iter = vec![Some(1), None, Some(3)].into_iter();
+/// let iter = [Some(1), None, Some(3)].into_iter();
/// let filtered = iter.filter_map(identity).collect::<Vec<_>>();
/// assert_eq!(vec![1, 3], filtered);
/// ```
/// `TryFrom<T>` can be implemented as follows:
///
/// ```
-/// use std::convert::TryFrom;
-///
/// struct GreaterThanZero(i32);
///
/// impl TryFrom<i32> for GreaterThanZero {
/// As described, [`i32`] implements `TryFrom<`[`i64`]`>`:
///
/// ```
-/// use std::convert::TryFrom;
-///
/// let big_number = 1_000_000_000_000i64;
/// // Silently truncates `big_number`, requires detecting
/// // and handling the truncation after the fact.
/// Below are common applications of `transmute` which can be replaced with safer
/// constructs.
///
- /// Turning raw bytes(`&[u8]`) to `u32`, `f64`, etc.:
+ /// Turning raw bytes (`&[u8]`) into `u32`, `f64`, etc.:
///
/// ```
/// let raw_bytes = [0x78, 0x56, 0x34, 0x12];
/// you can also [`map`] backwards:
///
/// ```rust
-/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
+/// let v: Vec<i32> = [1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
///
/// assert_eq!(v, [4, 3, 2]);
/// ```
/// ```rust
/// let mut c = 0;
///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) }) {
/// println!("{:?}", pair);
/// }
/// ```rust
/// let mut c = 0;
///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
/// .map(|letter| { c += 1; (letter, c) })
/// .rev() {
/// println!("{:?}", pair);
mod take_while;
mod zip;
+#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap,
flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev,
mod repeat_with;
mod successors;
+#[stable(feature = "rust1", since = "1.0.0")]
pub use self::repeat::{repeat, Repeat};
#[stable(feature = "iter_empty", since = "1.2.0")]
/// Basic usage:
///
/// ```
-/// use std::iter::FromIterator;
-///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
/// Implementing `FromIterator` for your type:
///
/// ```
-/// use std::iter::FromIterator;
-///
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
/// Basic usage:
///
/// ```
- /// use std::iter::FromIterator;
- ///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
/// Basic usage:
///
/// ```
-/// let v = vec![1, 2, 3];
+/// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
/// Basic usage:
///
/// ```
- /// let v = vec![1, 2, 3];
+ /// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
/// #[derive(PartialEq, Debug)]
/// struct NotClone(usize);
///
- /// let v = vec![NotClone(0), NotClone(1), NotClone(2)];
+ /// let v = [NotClone(0), NotClone(1), NotClone(2)];
/// let mut it = v.into_iter().intersperse_with(|| NotClone(99));
///
/// assert_eq!(it.next(), Some(NotClone(0))); // The first element from `v`.
/// Stopping after an initial [`None`]:
///
/// ```
- /// use std::convert::TryFrom;
- ///
/// let a = [0, 1, 2, -3, 4, 5, -6];
///
/// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
/// removed:
///
/// ```
- /// use std::convert::TryFrom;
- ///
/// let a = [1, 2, -3, 4];
/// let mut iter = a.iter();
///
/// `take` will limit itself to the size of the underlying iterator:
///
/// ```
- /// let v = vec![1, 2];
+ /// let v = [1, 2];
/// let mut iter = v.into_iter().take(5);
/// assert_eq!(iter.next(), Some(1));
/// assert_eq!(iter.next(), Some(2));
/// Basic usage:
///
/// ```
- /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter();
+ /// let mut words = ["hello", "world", "of", "Rust"].into_iter();
///
/// // Take the first two words.
/// let hello_world: Vec<_> = words.by_ref().take(2).collect();
/// incomparable. You can work around this by using [`Iterator::reduce`]:
/// ```
/// assert_eq!(
- /// vec![2.4, f32::NAN, 1.3]
+ /// [2.4, f32::NAN, 1.3]
/// .into_iter()
/// .reduce(f32::max)
/// .unwrap(),
/// incomparable. You can work around this by using [`Iterator::reduce`]:
/// ```
/// assert_eq!(
- /// vec![2.4, f32::NAN, 1.3]
+ /// [2.4, f32::NAN, 1.3]
/// .into_iter()
/// .reduce(f32::min)
/// .unwrap(),
mod iterator;
mod marker;
-pub use self::accum::{Product, Sum};
-pub use self::collect::{Extend, FromIterator, IntoIterator};
-pub use self::double_ended::DoubleEndedIterator;
-pub use self::exact_size::ExactSizeIterator;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::iterator::Iterator;
+pub use self::{
+ accum::{Product, Sum},
+ collect::{Extend, FromIterator, IntoIterator},
+ double_ended::DoubleEndedIterator,
+ exact_size::ExactSizeIterator,
+ iterator::Iterator,
+ marker::{FusedIterator, TrustedLen},
+};
+
#[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable;
#[unstable(feature = "trusted_step", issue = "85731")]
pub use self::marker::TrustedStep;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::marker::{FusedIterator, TrustedLen};
/// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX`
/// the return value is unspecified. Uninhabited variants will be counted.
///
+/// Note that an enum may be expanded with additional variants in the future
+/// as a non-breaking change, for example if it is marked `#[non_exhaustive]`,
+/// which will change the result of this function.
+///
/// # Examples
///
/// ```
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[must_use = "this returns the result of the operation, without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn recip(self) -> f32 {
/// ```
///
/// If one of the arguments is NaN, then the other argument is returned.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f32) -> f32 {
/// ```
///
/// If one of the arguments is NaN, then the other argument is returned.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f32) -> f32 {
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
pub fn maximum(self, other: f32) -> f32 {
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
pub fn minimum(self, other: f32) -> f32 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[must_use = "this returns the result of the operation, without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn recip(self) -> f64 {
/// ```
///
/// If one of the arguments is NaN, then the other argument is returned.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f64) -> f64 {
/// ```
///
/// If one of the arguments is NaN, then the other argument is returned.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f64) -> f64 {
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
pub fn maximum(self, other: f64) -> f64 {
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ #[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
pub fn minimum(self, other: f64) -> f64 {
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
/// When starting from a slice rather than an array, fallible conversion APIs can be used:
///
/// ```
- /// use std::convert::TryInto;
- ///
#[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
#[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
/// *input = rest;
//! let mut bt = BTreeMap::new();
//! bt.insert(20u8, "foo");
//! bt.insert(42u8, "bar");
-//! let res = vec![0u8, 1, 11, 200, 22]
+//! let res = [0u8, 1, 11, 200, 22]
//! .into_iter()
//! .map(|x| {
//! // `checked_sub()` returns `None` on error
//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E
//!
//! ```
-//! let v = vec![Some(2), Some(4), None, Some(8)];
+//! let v = [Some(2), Some(4), None, Some(8)];
//! let res: Option<Vec<_>> = v.into_iter().collect();
//! assert_eq!(res, None);
-//! let v = vec![Some(2), Some(4), Some(8)];
+//! let v = [Some(2), Some(4), Some(8)];
//! let res: Option<Vec<_>> = v.into_iter().collect();
//! assert_eq!(res, Some(vec![2, 4, 8]));
//! ```
//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E
//!
//! ```
-//! let v = vec![None, Some(1), Some(2), Some(3)];
+//! let v = [None, Some(1), Some(2), Some(3)];
//! let res: Option<i32> = v.into_iter().sum();
//! assert_eq!(res, None);
-//! let v = vec![Some(1), Some(2), Some(21)];
+//! let v = [Some(1), Some(2), Some(21)];
//! let res: Option<i32> = v.into_iter().product();
//! assert_eq!(res, Some(42));
//! ```
#[inline]
#[track_caller]
#[lang = "panic_str"] // needed for `non-fmt-panics` lint
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_str(expr: &str) -> ! {
panic_display(&expr);
}
#[track_caller]
#[lang = "panic_display"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
/// This function is used instead of panic_fmt in const eval.
#[lang = "const_panic_fmt"]
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if let Some(msg) = fmt.as_str() {
panic_str(msg);
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.
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.
//! # use std::str::FromStr;
//! let mut results = vec![];
//! let mut errs = vec![];
-//! let nums: Vec<_> = vec!["17", "not a number", "99", "-27", "768"]
+//! let nums: Vec<_> = ["17", "not a number", "99", "-27", "768"]
//! .into_iter()
//! .map(u8::from_str)
//! // Save clones of the raw `Result` values to inspect
//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E
//!
//! ```
-//! let v = vec![Ok(2), Ok(4), Err("err!"), Ok(8)];
+//! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)];
//! let res: Result<Vec<_>, &str> = v.into_iter().collect();
//! assert_eq!(res, Err("err!"));
-//! let v = vec![Ok(2), Ok(4), Ok(8)];
+//! let v = [Ok(2), Ok(4), Ok(8)];
//! let res: Result<Vec<_>, &str> = v.into_iter().collect();
//! assert_eq!(res, Ok(vec![2, 4, 8]));
//! ```
//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E
//!
//! ```
-//! let v = vec![Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
+//! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
//! let res: Result<i32, &str> = v.into_iter().sum();
//! assert_eq!(res, Err("error!"));
-//! let v: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Ok(21)];
+//! let v = [Ok(1), Ok(2), Ok(21)];
//! let res: Result<i32, &str> = v.into_iter().product();
//! assert_eq!(res, Ok(42));
//! ```
#[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.
#[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.
#[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.
struct NotClone {
u: u32,
}
- let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
+ let r = [NotClone { u: 0 }, NotClone { u: 1 }]
.into_iter()
.intersperse_with(|| NotClone { u: 2 })
.collect::<Vec<_>>();
#[test]
fn test_intersperse_collect_string() {
- let contents = vec![1, 2, 3];
+ let contents = [1, 2, 3];
let contents_string = contents
.into_iter()
#[test]
fn test_iterator_peekable_next_if_eq() {
// first, try on references
- let xs = vec!["Heart", "of", "Gold"];
+ let xs = ["Heart", "of", "Gold"];
let mut it = xs.into_iter().peekable();
// try before `peek()`
assert_eq!(it.next_if_eq(&"trillian"), None);
assert_eq!(it.next(), Some("Gold"));
// make sure comparison works for owned values
- let xs = vec![String::from("Ludicrous"), "speed".into()];
+ let xs = [String::from("Ludicrous"), "speed".into()];
let mut it = xs.into_iter().peekable();
// make sure basic functionality works
assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
#[test]
fn test_iterator_peekable_mut() {
- let mut it = vec![1, 2, 3].into_iter().peekable();
+ let mut it = [1, 2, 3].into_iter().peekable();
if let Some(p) = it.peek_mut() {
if *p == 1 {
*p = 5;
#[test]
fn test_try_reduce() {
- let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+ let v = [1usize, 2, 3, 4, 5];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, Some(Some(15)));
- let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+ let v = [1, 2, 3, 4, 5, usize::MAX];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, None);
- let v: Vec<usize> = Vec::new();
+ let v: [usize; 0] = [];
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
assert_eq!(sum, Some(None));
- let v = vec!["1", "2", "3", "4", "5"];
+ let v = ["1", "2", "3", "4", "5"];
let max = v.into_iter().try_reduce(|x, y| {
if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
});
assert_eq!(max, Some(Some("5")));
- let v = vec!["1", "2", "3", "4", "5"];
+ let v = ["1", "2", "3", "4", "5"];
let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
v.into_iter().try_reduce(|x, y| {
if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via process aborts"
-edition = "2018"
+edition = "2021"
[lib]
test = false
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via stack unwinding"
-edition = "2018"
+edition = "2021"
[lib]
test = false
[package]
name = "proc_macro"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[dependencies]
std = { path = "../std" }
[package]
name = "profiler_builtins"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[lib]
test = false
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
description = """
Hack for the compiler's own build system
"""
-edition = "2018"
+edition = "2021"
[lib]
path = "lib.rs"
#[test]
fn test_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let keys: Vec<_> = map.keys().cloned().collect();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
#[test]
fn test_values() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let values: Vec<_> = map.values().cloned().collect();
assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
#[test]
fn test_values_mut() {
- let vec = vec![(1, 1), (2, 2), (3, 3)];
- let mut map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 1), (2, 2), (3, 3)];
+ let mut map: HashMap<_, _> = pairs.into_iter().collect();
for value in map.values_mut() {
*value = (*value) * 2
}
#[test]
fn test_into_keys() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();
assert_eq!(keys.len(), 3);
#[test]
fn test_into_values() {
- let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
- let map: HashMap<_, _> = vec.into_iter().collect();
+ let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = pairs.into_iter().collect();
let values: Vec<_> = map.into_values().collect();
assert_eq!(values.len(), 3);
//! ```
//! use std::collections::VecDeque;
//!
-//! let vec = vec![1, 2, 3, 4];
+//! let vec = [1, 2, 3, 4];
//! let buf: VecDeque<_> = vec.into_iter().collect();
//! ```
//!
}
}
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl Error for char::TryFromCharError {}
+
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug + Ord, V: Debug> Error
for crate::collections::btree_map::OccupiedError<'a, K, V>
// Copied from `any.rs`.
impl dyn Error + 'static {
- /// Returns `true` if the boxed type is the same as `T`
+ /// Returns `true` if the inner type is the same as `T`.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
- // Get `TypeId` of the type in the trait object.
- let boxed = self.type_id(private::Internal);
+ // Get `TypeId` of the type in the trait object (`self`).
+ let concrete = self.type_id(private::Internal);
// Compare both `TypeId`s on equality.
- t == boxed
+ t == concrete
}
- /// Returns some reference to the boxed value if it is of type `T`, or
+ /// Returns some reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
}
}
- /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// Returns some mutable reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
/// open or create a file with specific options if `open()` or `create()`
/// are not appropriate.
///
- /// It is equivalent to `OpenOptions::new()` but allows you to write more
- /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
- /// you can write `File::options().read(true).open("foo.txt")`. This
+ /// It is equivalent to `OpenOptions::new()`, but allows you to write more
+ /// readable code. Instead of
+ /// `OpenOptions::new().append(true).open("example.log")`,
+ /// you can write `File::options().append(true).open("example.log")`. This
/// also avoids the need to import `OpenOptions`.
///
/// See the [`OpenOptions::new`] function for more details.
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
- /// let mut f = File::options().read(true).open("foo.txt")?;
+ /// let mut f = File::options().append(true).open("example.log")?;
/// Ok(())
/// }
/// ```
use crate::fmt;
use crate::io::Error;
-pub use bufreader::BufReader;
-pub use bufwriter::BufWriter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
+use linewritershim::LineWriterShim;
+
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use bufwriter::WriterPanicked;
-pub use linewriter::LineWriter;
-use linewritershim::LineWriterShim;
/// An error returned by [`BufWriter::into_inner`] which combines an error that
/// happened while writing out the buffer, and the buffered writer object
use crate::sys;
use crate::sys_common::memchr;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::IntoInnerError;
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use self::buffered::WriterPanicked;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::{BufReader, BufWriter, LineWriter};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::copy::copy;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::cursor::Cursor;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::error::{Error, ErrorKind, Result};
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
pub use self::stdio::set_output_capture;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
#[unstable(feature = "print_internals", issue = "none")]
pub use self::stdio::{_eprint, _print};
+#[unstable(feature = "stdio_locked", issue = "86845")]
+pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
+pub use self::{
+ buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
+ copy::copy,
+ cursor::Cursor,
+ error::{Error, ErrorKind, Result},
+ stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock},
+ util::{empty, repeat, sink, Empty, Repeat, Sink},
+};
#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::ReadBuf;
/// i.next().unwrap_or_else(I::Item::default)
/// }
///
-/// assert_eq!(first_or_default(vec![1, 2, 3].into_iter()), 1);
+/// assert_eq!(first_or_default([1, 2, 3].into_iter()), 1);
/// assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);
/// ```
///
//! development you may want to press the `[-]` button near the top of the
//! page to collapse it into a more skimmable view.
//!
-//! While you are looking at that `[-]` button also notice the `[src]`
-//! button. Rust's API documentation comes with the source code and you are
+//! While you are looking at that `[-]` button also notice the `source`
+//! link. Rust's API documentation comes with the source code and you are
//! encouraged to read it. The standard library source is generally high
//! quality and a peek behind the curtains is often enlightening.
//!
target_arch = "riscv32"
))]
mod arch {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
}
#![stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::os::fd::raw::*;
// exist after the thread has terminated, which is signaled by `Thread::join`
// returning.
native: unsafe {
- Some(imp::Thread::new(
+ imp::Thread::new(
stack_size,
mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(
Box::new(main),
),
- )?)
+ )?
},
thread: my_thread,
packet: Packet(my_packet),
/// Inner representation for JoinHandle
struct JoinInner<T> {
- native: Option<imp::Thread>,
+ native: imp::Thread,
thread: Thread,
packet: Packet<T>,
}
impl<T> JoinInner<T> {
- fn join(&mut self) -> Result<T> {
- self.native.take().unwrap().join();
- unsafe { (*self.packet.0.get()).take().unwrap() }
+ fn join(mut self) -> Result<T> {
+ self.native.join();
+ Arc::get_mut(&mut self.packet.0).unwrap().get_mut().take().unwrap()
}
}
/// join_handle.join().expect("Couldn't join on the associated thread");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn join(mut self) -> Result<T> {
+ pub fn join(self) -> Result<T> {
self.0.join()
}
impl<T> AsInner<imp::Thread> for JoinHandle<T> {
fn as_inner(&self) -> &imp::Thread {
- self.0.native.as_ref().unwrap()
+ &self.0.native
}
}
impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
fn into_inner(self) -> imp::Thread {
- self.0.native.unwrap()
+ self.0.native
}
}
///
/// ```
/// # #![allow(dead_code)]
-/// #![feature(available_parallelism)]
/// use std::{io, thread};
///
/// fn main() -> io::Result<()> {
#[doc(alias = "available_concurrency")] // Alias for a previous name we gave this API on unstable.
#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`.
#[doc(alias = "num_cpus")] // Alias for a popular ecosystem crate which provides similar functionality.
-#[unstable(feature = "available_parallelism", issue = "74479")]
+#[stable(feature = "available_parallelism", since = "1.59.0")]
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
imp::available_parallelism()
}
/// instant when created, and are often useful for tasks such as measuring
/// benchmarks or timing how long an operation takes.
///
-/// Note, however, that instants are not guaranteed to be **steady**. In other
+/// Note, however, that instants are **not** guaranteed to be **steady**. In other
/// words, each tick of the underlying clock might not be the same length (e.g.
/// some seconds may be longer than others). An instant may jump forwards or
/// experience time dilation (slow down or speed up), but it will never go
[package]
name = "test"
version = "0.0.0"
-edition = "2018"
+edition = "2021"
[lib]
crate-type = ["dylib", "rlib"]
#![unstable(feature = "test", issue = "50297")]
#![doc(test(attr(deny(warnings))))]
#![feature(nll)]
-#![feature(available_parallelism)]
#![feature(bench_black_box)]
#![feature(internal_output_capture)]
#![feature(staged_api)]
#[test]
pub fn exact_filter_match() {
fn tests() -> Vec<TestDescAndFn> {
- vec!["base", "base::test", "base::test1", "base::test2"]
+ ["base", "base::test", "base::test1", "base::test2"]
.into_iter()
.map(|name| TestDescAndFn {
desc: TestDesc {
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
-edition = "2018"
+edition = "2021"
include = [
'/libunwind/*',
]
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
/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
git checkout a54eb56f33f255dfca60be045f12a5cfaf5a72a9
# Fix the cfi detection script in musl's configure so cfi is generated
-# when debug info is asked for.
+# when debug info is asked for. This patch is derived from
+# https://git.musl-libc.org/cgit/musl/commit/?id=c4d4028dde90562f631edf559fbc42d8ec1b29de.
+# When we upgrade to a version that includes this commit, we can remove the patch.
mkdir patches/musl-1.1.24
cp ../musl-patch-configure.diff patches/musl-1.1.24/0001-fix-cfi-detection.diff
The `no_run` attribute will compile your code but not run it. This is
important for examples such as "Here's how to retrieve a web page,"
which you would want to ensure compiles, but might be run in a test
-environment that has no network access.
+environment that has no network access. This attribute can also be
+used to demonstrate code snippets that can cause Undefined Behavior.
```rust
/// ```no_run
[dependencies]
arrayvec = { version = "0.7", default-features = false }
+askama = { version = "0.11", default-features = false }
pulldown-cmark = { version = "0.9", default-features = false }
minifier = "0.0.41"
rayon = "1.3.1"
rustdoc-json-types = { path = "../rustdoc-json-types" }
tracing = "0.1"
tracing-tree = "0.2.0"
-tera = { version = "1.10.0", default-features = false }
[dependencies.tracing-subscriber]
version = "0.3.3"
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);
+ 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);
- let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let trait_ref = trait_ref.subst(infcx.tcx, impl_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);
+ // 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(),
+ trace!(
+ "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
param_env,
- predicate,
+ trait_ref,
+ ty
);
- match infcx.evaluate_obligation(&obligation) {
- Ok(eval_result) if eval_result.may_apply() => {}
- Err(traits::OverflowError::Canonical) => {}
- Err(traits::OverflowError::ErrorReporting) => {}
- _ => {
- return false;
+ 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
}
- true
- } else {
- false
+ });
+ debug!(
+ "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
+ may_apply, trait_ref, ty
+ );
+ if !may_apply {
+ continue;
}
- });
- debug!(
- "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
- may_apply, trait_ref, ty
- );
- if !may_apply {
- continue;
- }
- self.cx.generated_synthetics.insert((ty, trait_def_id));
+ 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(
- 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,
- });
+ 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
}
}
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
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);
// If we're re-exporting a re-export it may actually re-export something in
// two namespaces, so the target may be listed twice. Make sure we only
// visit each node at most once.
- for &item in cx.tcx.item_children(did).iter() {
+ for &item in cx.tcx.module_children(did).iter() {
if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() {
impl Clean<Item> for ty::FieldDef {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
- clean_field(self.did, self.ident.name, cx.tcx.type_of(self.did).clean(cx), cx)
+ clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx)
}
}
}),
};
let what_rustc_thinks =
- Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), VariantItem(kind), cx);
+ Item::from_def_id_and_parts(self.def_id, Some(self.name), VariantItem(kind), cx);
// don't show `pub` for variants, which always inherit visibility
Item { visibility: Inherited, ..what_rustc_thinks }
}
use std::cell::RefCell;
use std::default::Default;
-use std::fmt::Write;
use std::hash::Hash;
use std::lazy::SyncOnceCell as OnceCell;
use std::path::PathBuf;
})
.collect()
} else {
- tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+ tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
}
}
})
.collect()
} else {
- tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
+ tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
}
}
}
if let Ok((mut href, ..)) = href(*did, cx) {
debug!(?href);
if let Some(ref fragment) = *fragment {
- write!(href, "{}", fragment).unwrap()
+ fragment.render(&mut href, cx.tcx()).unwrap()
}
Some(RenderedLink {
original_text: s.clone(),
let mut out = String::new();
add_doc_fragment(&mut out, ori);
for new_frag in iter {
- if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
- break;
- }
add_doc_fragment(&mut out, new_frag);
}
out.pop();
};
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);
}
/// If present, playground URL to use in the "Run" button added to code samples generated from
/// standalone Markdown files. If not present, `playground_url` is used.
crate markdown_playground_url: Option<String>,
- /// If false, the `select` element to have search filtering by crates on rendered docs
- /// won't be generated.
- crate generate_search_filter: bool,
/// Document items that have lower than `pub` visibility.
crate document_private: bool,
/// Document items that have `doc(hidden)`.
let crate_version = matches.opt_str("crate-version");
let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
let static_root_path = matches.opt_str("static-root-path");
- let generate_search_filter = !matches.opt_present("disable-per-crate-search");
let test_run_directory = matches.opt_str("test-run-directory").map(PathBuf::from);
let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
markdown_no_toc,
markdown_css,
markdown_playground_url,
- generate_search_filter,
document_private,
document_hidden,
generate_redirect_map,
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;
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.
_ => 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.
}
}
-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,
});
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(),
};
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(),
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};
-use serde::Serialize;
+use askama::Template;
-#[derive(Clone, Serialize)]
+#[derive(Clone)]
crate struct Layout {
crate logo: String,
crate favicon: String,
/// The given user css file which allow to customize the generated
/// documentation theme.
crate css_file_extension: Option<PathBuf>,
- /// If false, the `select` element to have search filtering by crates on rendered docs
- /// won't be generated.
- crate generate_search_filter: bool,
/// If true, then scrape-examples.js will be included in the output HTML file
crate scrape_examples_extension: bool,
}
-#[derive(Serialize)]
crate struct Page<'a> {
crate title: &'a str,
crate css_class: &'a str,
}
}
-#[derive(Serialize)]
+#[derive(Template)]
+#[template(path = "page.html")]
struct PageLayout<'a> {
static_root_path: &'a str,
page: &'a Page<'a>,
}
crate fn render<T: Print, S: Print>(
- templates: &tera::Tera,
layout: &Layout,
page: &Page<'_>,
sidebar: S,
let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
let sidebar = Buffer::html().to_display(sidebar);
- let teractx = tera::Context::from_serialize(PageLayout {
+ PageLayout {
static_root_path,
page,
layout,
content,
krate_with_trailing_slash,
rustdoc_version,
- })
- .unwrap();
- templates.render("page.html", &teractx).unwrap()
+ }
+ .render()
+ .unwrap()
}
crate fn redirect(url: &str) -> String {
use super::print_item::{full_path, item_path, print_item};
use super::search_index::build_index;
-use super::templates;
use super::write_shared::write_shared;
use super::{
collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
///
/// [#82381]: https://github.com/rust-lang/rust/issues/82381
crate shared: Rc<SharedContext<'tcx>>,
- /// This flag indicates whether `[src]` links should be generated or not. If
+ /// This flag indicates whether source links should be generated or not. If
/// the source files are present in the html rendering, then this will be
/// `true`.
crate include_sources: bool,
/// the crate.
redirections: Option<RefCell<FxHashMap<String, String>>>,
- pub(crate) templates: tera::Tera,
-
/// Correspondance map used to link types used in the source code pages to allow to click on
/// links to jump to the type's definition.
crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
if !self.render_redirect_pages {
layout::render(
- &self.shared.templates,
&self.shared.layout,
&page,
|buf: &mut _| print_sidebar(self, it, buf),
- |buf: &mut _| print_item(self, &self.shared.templates, it, buf, &page),
+ |buf: &mut _| print_item(self, it, buf, &page),
&self.shared.style_files,
)
} else {
extension_css,
resource_suffix,
static_root_path,
- generate_search_filter,
unstable_features,
generate_redirect_map,
show_type_layout,
default_settings,
krate: krate.name(tcx).to_string(),
css_file_extension: extension_css,
- generate_search_filter,
scrape_examples_extension: !call_locations.is_empty(),
};
let mut issue_tracker_base_url = None;
let mut include_sources = true;
- let templates = templates::load()?;
// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
errors: receiver,
redirections: if generate_redirect_map { Some(Default::default()) } else { None },
show_type_layout,
- templates,
span_correspondance_map: matches,
cache,
call_locations,
};
let all = self.shared.all.replace(AllTypes::new());
let v = layout::render(
- &self.shared.templates,
&self.shared.layout,
&page,
sidebar,
.map(StylePath::basename)
.collect::<Result<_, Error>>()?;
let v = layout::render(
- &self.shared.templates,
&self.shared.layout,
&page,
sidebar,
_ => unreachable!(),
};
let items = self.build_sidebar_items(module);
- let js_dst = self.dst.join("sidebar-items.js");
+ let js_dst = self.dst.join(&format!("sidebar-items{}.js", self.shared.resource_suffix));
let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap());
scx.fs.write(js_dst, v)?;
}
mod context;
mod print_item;
mod span_map;
-mod templates;
mod write_shared;
crate use self::context::*;
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
if let Some(l) = cx.src_href(item) {
- write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
+ write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">source</a>", l)
}
}
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
const_stability: Option<ConstStability>,
containing_ver: Option<Symbol>,
containing_const_ver: Option<Symbol>,
-) {
+) -> bool {
let ver = ver.filter(|inner| !inner.is_empty());
match (ver, const_stability) {
v
);
}
- _ => {}
+ _ => return false,
}
+ true
}
fn render_assoc_item(
}
// Render the items that appear on the right side of methods, impls, and
-// associated types. For example "1.0.0 (const: 1.39.0) [src]".
+// associated types. For example "1.0.0 (const: 1.39.0) · source".
fn render_rightside(
w: &mut Buffer,
cx: &Context<'_>,
};
write!(w, "<div class=\"rightside\">");
- render_stability_since_raw(
+ let has_stability = render_stability_since_raw(
w,
item.stable_since(tcx),
const_stability,
containing_item.stable_since(tcx),
const_stable_since,
);
+ if has_stability {
+ w.write_str(" · ");
+ }
write_srclink(cx, item, w);
w.write_str("</div>");
ty = it.type_(),
path = relpath
);
- write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
+ write!(
+ buffer,
+ "<script defer src=\"{}sidebar-items{}.js\"></script>",
+ relpath, cx.shared.resource_suffix
+ );
// Closes sidebar-elems div.
buffer.write_str("</div>");
}
use crate::html::layout::Page;
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
-use serde::Serialize;
+use askama::Template;
const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
const ITEM_TABLE_CLOSE: &str = "</div>";
const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
// A component in a `use` path, like `string` in std::string::ToString
-#[derive(Serialize)]
struct PathComponent<'a> {
path: String,
name: &'a str,
}
-#[derive(Serialize)]
+#[derive(Template)]
+#[template(path = "print_item.html")]
struct ItemVars<'a> {
page: &'a Page<'a>,
static_root_path: &'a str,
src_href: Option<&'a str>,
}
-pub(super) fn print_item(
- cx: &Context<'_>,
- templates: &tera::Tera,
- item: &clean::Item,
- buf: &mut Buffer,
- page: &Page<'_>,
-) {
+pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>) {
debug_assert!(!item.is_stripped());
let typ = match *item.kind {
clean::ModuleItem(_) => {
);
let stability_since_raw: String = stability_since_raw.into_inner();
- // Write `src` tag
+ // Write source tag
//
// When this item is part of a `crate use` in a downstream crate, the
- // [src] link in the downstream documentation will actually come back to
+ // source link in the downstream documentation will actually come back to
// this page, and this link will be auto-clicked. The `id` attribute is
// used to find the link to auto-click.
let src_href =
src_href: src_href.as_deref(),
};
- let teractx = tera::Context::from_serialize(item_vars).unwrap();
- let heading = templates.render("print_item.html", &teractx).unwrap();
+ let heading = item_vars.render().unwrap();
buf.write_str(&heading);
match *item.kind {
item.const_stability(tcx),
containing_item.stable_since(tcx),
containing_item.const_stable_since(tcx),
- )
+ );
}
fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
}
if it.has_stripped_fields().unwrap() {
- write!(w, " // some fields omitted\n{}", tab);
+ write!(w, " /* private fields */\n{}", tab);
}
if toggle {
toggle_close(w);
if has_visible_fields {
if it.has_stripped_fields().unwrap() {
- write!(w, "\n{} // some fields omitted", tab);
+ write!(w, "\n{} /* private fields */", tab);
}
write!(w, "\n{}", tab);
} else if it.has_stripped_fields().unwrap() {
- // If there are no visible fields we can just display
- // `{ /* fields omitted */ }` to save space.
- write!(w, " /* fields omitted */ ");
+ write!(w, " /* private fields */ ");
}
if toggle {
toggle_close(w);
};
for (index, layout) in variants.iter_enumerated() {
- let ident = adt.variants[index].ident;
- write!(w, "<li><code>{name}</code>: ", name = ident);
+ let name = adt.variants[index].name;
+ write!(w, "<li><code>{name}</code>: ", name = name);
write_size_of_layout(w, layout, tag_size);
writeln!(w, "</li>");
}
+++ /dev/null
-use std::error::Error as StdError;
-
-use crate::error::Error;
-
-pub(crate) fn load() -> Result<tera::Tera, Error> {
- let mut templates = tera::Tera::default();
-
- macro_rules! include_template {
- ($file:literal, $fullpath:literal) => {
- templates.add_raw_template($file, include_str!($fullpath)).map_err(|e| Error {
- file: $file.into(),
- error: format!("{}: {}", e, e.source().map(|e| e.to_string()).unwrap_or_default()),
- })?
- };
- }
-
- include_template!("page.html", "../templates/page.html");
- include_template!("print_item.html", "../templates/print_item.html");
- Ok(templates)
-}
})
.collect::<String>()
);
- let v = layout::render(
- &cx.shared.templates,
- &cx.shared.layout,
- &page,
- "",
- content,
- &cx.shared.style_files,
- );
+ let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.style_files);
cx.shared.fs.write(dst, v)?;
}
}
static_extra_scripts: &[&format!("source-script{}", self.cx.shared.resource_suffix)],
};
let v = layout::render(
- &self.cx.shared.templates,
&self.cx.shared.layout,
&page,
"",
margin: 15px 0 5px 0;
}
h1.fqn {
+ margin: 0;
+ padding: 0;
+}
+.main-heading {
display: flex;
- border-bottom: 1px dashed;
- margin-top: 0;
+ border-bottom: 1px dashed #DDDDDD;
+ padding-bottom: 6px;
+ margin-bottom: 15px;
/* workaround to keep flex from breaking below 700 px width due to the float: right on the nav
above the h1 */
padding-left: 1px;
}
-h1.fqn > .in-band > a:hover {
+.main-heading a:hover {
text-decoration: underline;
}
+#toggle-all-docs {
+ text-decoration: none;
+}
/* The only headings that get underlines are:
Markdown-generated headings within the top-doc
Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
.sidebar, a.source, .search-input, .search-results .result-name,
.content table td:first-child > a,
.item-left > a,
-div.item-list .out-of-band, span.since,
+.out-of-band,
+span.since,
#source-sidebar, #sidebar-toggle,
details.rustdoc-toggle > summary::before,
div.impl-items > div:not(.docblock):not(.item-info),
-.content ul.crate a.crate, a.srclink,
+.content ul.crate a.crate,
+a.srclink,
/* This selector is for the items listed in the "all items" page. */
#main-content > ul.docblock > li > a {
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
position: relative;
}
+.search-loading {
+ text-align: center;
+}
+
#results > table {
width: 100%;
table-layout: fixed;
.content .out-of-band {
flex-grow: 0;
text-align: right;
- font-size: 1.4375rem;
- margin: 0px;
+ margin-left: auto;
+ margin-right: 0;
+ font-size: 1.15rem;
padding: 0 0 0 12px;
font-weight: normal;
+ float: right;
}
.method > .code-header, .trait-impl > .code-header, .invisible > .code-header {
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 */
font-size: initial;
}
-.impl-items .since, .impl .since, .methods .since {
+.rightside {
padding-left: 12px;
padding-right: 2px;
position: initial;
font-weight: 300;
}
-.since + .srclink {
- padding-left: 10px;
-}
-
.item-spacer {
width: 100%;
height: 12px;
background-color: #14191f;
}
-.rust-logo > img {
+.rust-logo {
filter: drop-shadow(1px 0 0px #fff)
drop-shadow(0 1px 0 #fff)
drop-shadow(-1px 0 0 #fff)
a {
color: #39AFD7;
}
-a.srclink,
+
a#toggle-all-docs,
a.anchor,
.small-section-header a,
background-color: #505050;
}
-.rust-logo > img {
+.rust-logo {
filter: drop-shadow(1px 0 0px #fff)
drop-shadow(0 1px 0 #fff)
drop-shadow(-1px 0 0 #fff)
a {
color: #D2991D;
}
-a.srclink,
+
a#toggle-all-docs,
a.anchor,
.small-section-header a,
scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
}
-.rust-logo > img {
+.rust-logo {
/* No need for a border in here! */
}
a {
color: #3873AD;
}
-a.srclink,
+
a#toggle-all-docs,
a.anchor,
.small-section-header a,
border-color: #bfbfbf;
}
-.since {
- color: grey;
-}
-
.result-name .primitive > i, .result-name .keyword > i {
color: black;
}
var params = searchState.getQueryStringParams();
if (params.search !== undefined) {
var search = searchState.outputElement();
- search.innerHTML = "<h3 style=\"text-align: center;\">" +
- searchState.loadingText + "</h3>";
+ search.innerHTML = "<h3 class=\"search-loading\">" +
+ searchState.loadingText + "</h3>";
searchState.showResults(search);
loadSearch();
}
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"
}
}
- 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]) +
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];
}
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) {
}
});
-
- 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()) {
};
}
+ 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.
+++ /dev/null
-# Style for Templates
-
-This directory has templates in the [Tera templating language](teradoc), which is very
-similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc).
-
-[teradoc]: https://tera.netlify.app/docs/#templates
-[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/
-[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/
-[askamadoc]: https://docs.rs/askama/0.10.5/askama/
-
-We want our rendered output to have as little unnecessary whitespace as
-possible, so that pages load quickly. To achieve that we use Tera's
-[whitespace control] features. At the end of most lines, we put an empty comment
-tag with the whitespace control characters: `{#- -#}`. This causes all
-whitespace between the end of the line and the beginning of the next, including
-indentation, to be omitted on render. Sometimes we want to preserve a single
-space. In those cases we put the space at the end of the line, followed by
-`{# -#}`, which is a directive to remove following whitespace but not preceding.
-We also use the whitespace control characters in most instances of tags with
-control flow, for example `{%- if foo -%}`.
-
-[whitespace control]: https://tera.netlify.app/docs/#whitespace-control
-
-We want our templates to be readable, so we use indentation and newlines
-liberally. We indent by four spaces after opening an HTML tag _or_ a Tera
-tag. In most cases an HTML tag should be followed by a newline, but if the
-tag has simple contents and fits with its close tag on a single line, the
-contents don't necessarily need a new line.
-
-Tera templates support quite sophisticated control flow. To keep our templates
-simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic](assignments) and [Tera
-macros](macros). This also may make things easier if we switch to a different
-Jinja-style template system, like Askama, in the future.
-
-[assignments]: https://tera.netlify.app/docs/#assignments
-[macros]: https://tera.netlify.app/docs/#macros
+++ /dev/null
-<!DOCTYPE html> {#- -#}
-<html lang="en"> {#- -#}
-<head> {#- -#}
- <meta charset="utf-8"> {#- -#}
- <meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
- <meta name="generator" content="rustdoc"> {#- -#}
- <meta name="description" content="{{page.description}}"> {#- -#}
- <meta name="keywords" content="{{page.keywords}}"> {#- -#}
- <title>{{page.title}}</title> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
- <link rel="stylesheet" type="text/css" {# -#}
- href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
- <link rel="stylesheet" type="text/css" {# -#}
- href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
- id="mainThemeStyle"> {#- -#}
- {%- for theme in themes -%}
- <link rel="stylesheet" type="text/css" {# -#}
- href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
- {%- if theme == "light" -%}
- id="themeStyle"
- {%- else -%}
- disabled
- {%- endif -%}
- >
- {%- endfor -%}
- <script id="default-settings" {# -#}
- {% for k, v in layout.default_settings %}
- data-{{k}}="{{v}}"
- {%- endfor -%}
- ></script> {#- -#}
- <script src="{{static_root_path | safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
- <script src="{{page.root_path | safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
- <script defer src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
- {%- for script in page.static_extra_scripts -%}
- <script defer src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
- {% endfor %}
- {%- if layout.scrape_examples_extension -%}
- <script defer src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
- {%- endif -%}
- {%- for script in page.extra_scripts -%}
- <script defer src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#}
- {% endfor %}
- <noscript> {#- -#}
- <link rel="stylesheet" {# -#}
- href="{{static_root_path | safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
- </noscript> {#- -#}
- {%- if layout.css_file_extension -%}
- <link rel="stylesheet" type="text/css" {# -#}
- href="{{static_root_path | safe}}theme{{page.resource_suffix}}.css"> {#- -#}
- {%- endif -%}
- {%- if layout.favicon -%}
- <link rel="shortcut icon" href="{{layout.favicon}}"> {#- -#}
- {%- else -%}
- <link rel="alternate icon" type="image/png" {# -#}
- href="{{static_root_path | safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
- <link rel="alternate icon" type="image/png" {# -#}
- href="{{static_root_path | safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
- <link rel="icon" type="image/svg+xml" {# -#}
- href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
- {%- endif -%}
- {{- layout.external_html.in_header | safe -}}
-</head> {#- -#}
-<body class="rustdoc {{page.css_class}}"> {#- -#}
- <!--[if lte IE 11]> {#- -#}
- <div class="warning"> {#- -#}
- This old browser is unsupported and will most likely display funky things. {#- -#}
- </div> {#- -#}
- <![endif]--> {#- -#}
- {{- layout.external_html.before_content | safe -}}
- <nav class="sidebar"> {#- -#}
- <div class="sidebar-menu" role="button">☰</div> {#- -#}
- <a class="sidebar-logo" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
- <div class="logo-container"> {#- -#}
- {%- if layout.logo -%}
- <img src="{{layout.logo}}" alt="logo"> {#- -#}
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
- {%- endif -%}
- </div>
- </a> {#- -#}
- {{- sidebar | safe -}}
- </nav> {#- -#}
- <main> {#- -#}
- <div class="width-limiter"> {#- -#}
- <div class="sub-container"> {#- -#}
- <a class="sub-logo-container" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
- {%- if layout.logo -%}
- <img src="{{layout.logo}}" alt="logo">
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo">
- {%- endif -%}
- </a> {#- -#}
- <nav class="sub"> {#- -#}
- <div class="theme-picker"> {#- -#}
- <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
- <img width="18" height="18" alt="Pick another theme!" {# -#}
- src="{{static_root_path | safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
- </button> {#- -#}
- <div id="theme-choices" role="menu"></div> {#- -#}
- </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 -%}
- <input {# -#}
- class="search-input" {# -#}
- name="search" {# -#}
- autocomplete="off" {# -#}
- spellcheck="false" {# -#}
- placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
- type="search"> {#- -#}
- </div> {#- -#}
- <button type="button" id="help-button" title="help">?</button> {#- -#}
- <a id="settings-menu" href="{{page.root_path | safe}}settings.html" title="settings"> {#- -#}
- <img width="18" height="18" alt="Change settings" {# -#}
- src="{{static_root_path | safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
- </a> {#- -#}
- </div> {#- -#}
- </form> {#- -#}
- </nav> {#- -#}
- </div> {#- -#}
- <section id="main-content" class="content">{{- content | safe -}}</section> {#- -#}
- <section id="search" class="content hidden"></section> {#- -#}
- </div> {#- -#}
- </main> {#- -#}
- {{- layout.external_html.after_content | safe -}}
- <div id="rustdoc-vars" {# -#}
- data-root-path="{{page.root_path | safe}}" {# -#}
- data-current-crate="{{layout.krate}}" {# -#}
- data-themes="{{themes | join(sep=",") }}" {# -#}
- data-resource-suffix="{{page.resource_suffix}}" {# -#}
- data-rustdoc-version="{{rustdoc_version}}" {# -#}
- > {#- -#}
- </div>
-</body> {#- -#}
-</html> {#- -#}
+++ /dev/null
-<h1 class="fqn"> {#- -#}
- <span class="in-band"> {#- -#}
- {{-typ-}}
- {#- The breadcrumbs of the item path, like std::string -#}
- {%- for component in path_components -%}
- <a href="{{component.path | safe}}index.html">{{component.name}}</a>::<wbr>
- {%- endfor -%}
- <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
- <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
- <img src="{{static_root_path | safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
- width="19" height="18" {# -#}
- alt="Copy item path"> {#- -#}
- </button> {#- -#}
- </span> {#- -#}
- <span class="out-of-band"> {#- -#}
- {{- stability_since_raw | safe -}}
- <span id="render-detail"> {#- -#}
- <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
- [<span class="inner">−</span>] {#- -#}
- </a> {#- -#}
- </span> {#- -#}
- {%- if src_href -%}
- <a class="srclink" href="{{src_href | safe}}" title="goto source code">[src]</a>
- {%- endif -%}
- </span> {#- -#}
-</h1> {#- -#}
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.
///
// 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");
core::run_global_ctxt(
tcx,
resolver,
+ resolver_caches,
show_coverage,
render_options,
output_format,
PerNS,
};
use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::ParentScope;
use rustc_session::lint::Lint;
use pulldown_cmark::LinkType;
use std::borrow::Cow;
-use std::cell::Cell;
use std::convert::{TryFrom, TryInto};
+use std::fmt::Write;
use std::mem;
use std::ops::Range;
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",
};
fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- let mut collector = LinkCollector {
- cx,
- mod_ids: Vec::new(),
- kind_side_channel: Cell::new(None),
- visited_links: FxHashMap::default(),
- };
+ let mut collector =
+ LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() };
collector.visit_crate(&krate);
krate
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
crate enum UrlFragment {
- Method(Symbol),
- TyMethod(Symbol),
- AssociatedConstant(Symbol),
- AssociatedType(Symbol),
-
- StructField(Symbol),
- Variant(Symbol),
- VariantField { variant: Symbol, field: Symbol },
-
+ Item(ItemFragment),
UserWritten(String),
}
impl UrlFragment {
+ /// Render the fragment, including the leading `#`.
+ crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
+ match self {
+ UrlFragment::Item(frag) => frag.render(s, tcx),
+ UrlFragment::UserWritten(raw) => write!(s, "#{}", raw),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+crate struct ItemFragment(FragmentKind, DefId);
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+crate enum FragmentKind {
+ Method,
+ TyMethod,
+ AssociatedConstant,
+ AssociatedType,
+
+ StructField,
+ Variant,
+ VariantField,
+}
+
+impl ItemFragment {
/// Create a fragment for an associated item.
///
/// `is_prototype` is whether this associated item is a trait method
/// without a default definition.
- fn from_assoc_item(name: Symbol, kind: ty::AssocKind, is_prototype: bool) -> Self {
+ fn from_assoc_item(def_id: DefId, kind: ty::AssocKind, is_prototype: bool) -> Self {
match kind {
ty::AssocKind::Fn => {
if is_prototype {
- UrlFragment::TyMethod(name)
+ ItemFragment(FragmentKind::TyMethod, def_id)
} else {
- UrlFragment::Method(name)
+ ItemFragment(FragmentKind::Method, def_id)
}
}
- ty::AssocKind::Const => UrlFragment::AssociatedConstant(name),
- ty::AssocKind::Type => UrlFragment::AssociatedType(name),
+ ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id),
+ ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id),
}
}
-}
-/// Render the fragment, including the leading `#`.
-impl std::fmt::Display for UrlFragment {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "#")?;
- match self {
- UrlFragment::Method(name) => write!(f, "method.{}", name),
- UrlFragment::TyMethod(name) => write!(f, "tymethod.{}", name),
- UrlFragment::AssociatedConstant(name) => write!(f, "associatedconstant.{}", name),
- UrlFragment::AssociatedType(name) => write!(f, "associatedtype.{}", name),
- UrlFragment::StructField(name) => write!(f, "structfield.{}", name),
- UrlFragment::Variant(name) => write!(f, "variant.{}", name),
- UrlFragment::VariantField { variant, field } => {
- write!(f, "variant.{}.field.{}", variant, field)
+ /// Render the fragment, including the leading `#`.
+ crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
+ write!(s, "#")?;
+ match *self {
+ ItemFragment(kind, def_id) => {
+ let name = tcx.item_name(def_id);
+ match kind {
+ FragmentKind::Method => write!(s, "method.{}", name),
+ FragmentKind::TyMethod => write!(s, "tymethod.{}", name),
+ FragmentKind::AssociatedConstant => write!(s, "associatedconstant.{}", name),
+ FragmentKind::AssociatedType => write!(s, "associatedtype.{}", name),
+ FragmentKind::StructField => write!(s, "structfield.{}", name),
+ FragmentKind::Variant => write!(s, "variant.{}", name),
+ FragmentKind::VariantField => {
+ let variant = tcx.item_name(tcx.parent(def_id).unwrap());
+ write!(s, "variant.{}.field.{}", variant, name)
+ }
+ }
}
- UrlFragment::UserWritten(raw) => write!(f, "{}", raw),
}
}
}
module_id: DefId,
dis: Option<Disambiguator>,
path_str: String,
- extra_fragment: Option<UrlFragment>,
+ extra_fragment: Option<String>,
}
#[derive(Clone)]
#[derive(Clone, Debug, Hash)]
struct CachedLink {
pub res: (Res, Option<UrlFragment>),
- pub side_channel: Option<(DefKind, DefId)>,
}
struct LinkCollector<'a, 'tcx> {
/// The last module will be used if the parent scope of the current item is
/// unknown.
mod_ids: Vec<DefId>,
- /// This is used to store the kind of associated items,
- /// because `clean` and the disambiguator code expect them to be different.
- /// See the code for associated items on inherent impls for details.
- kind_side_channel: Cell<Option<(DefKind, DefId)>>,
/// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link.
/// The link will be `None` if it could not be resolved (i.e. the error was cached).
visited_links: FxHashMap<ResolutionInfo, Option<CachedLink>>,
&self,
path_str: &'path str,
module_id: DefId,
- ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
+ ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
module_id,
}
match tcx.type_of(did).kind() {
ty::Adt(def, _) if def.is_enum() => {
- if def.all_fields().any(|item| item.ident.name == variant_field_name) {
- Ok((
- ty_res,
- Some(UrlFragment::VariantField {
- variant: variant_name,
- field: variant_field_name,
- }),
- ))
+ if let Some(field) =
+ def.all_fields().find(|f| f.ident(tcx).name == variant_field_name)
+ {
+ Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
} else {
Err(ResolutionFailure::NotResolved {
module_id,
prim_ty: PrimitiveType,
ns: Namespace,
item_name: Symbol,
- ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> {
+ ) -> Option<(Res, ItemFragment)> {
let tcx = self.cx.tcx;
prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
.map(|item| {
let kind = item.kind;
- let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
- (Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
+ let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+ (Res::Primitive(prim_ty), fragment)
})
})
}
path_str: &'path str,
ns: Namespace,
module_id: DefId,
- extra_fragment: &Option<UrlFragment>,
+ user_fragment: &Option<String>,
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
+ let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?;
+ let chosen_fragment = match (user_fragment, rustdoc_fragment) {
+ (Some(_), Some(r_frag)) => {
+ let diag_res = match r_frag {
+ ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did),
+ };
+ let failure = AnchorFailure::RustdocAnchorConflict(diag_res);
+ return Err(ErrorKind::AnchorFailure(failure));
+ }
+ (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())),
+ (None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)),
+ (None, None) => None,
+ };
+ Ok((res, chosen_fragment))
+ }
+
+ fn resolve_inner<'path>(
+ &mut self,
+ path_str: &'path str,
+ ns: Namespace,
+ module_id: DefId,
+ ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
if let Some(res) = self.resolve_path(path_str, ns, module_id) {
match res {
// FIXME(#76467): make this fallthrough to lookup the associated
Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS),
Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS),
Res::Def(DefKind::Variant, _) => {
- return handle_variant(self.cx, res, extra_fragment);
+ return handle_variant(self.cx, res);
}
// Not a trait item; just return what we found.
- _ => return Ok((res, extra_fragment.clone())),
+ _ => return Ok((res, None)),
}
}
resolve_primitive(&path_root, TypeNS)
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
.and_then(|ty_res| {
- let (res, fragment, side_channel) =
+ let (res, fragment) =
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
- let result = if extra_fragment.is_some() {
- // NOTE: can never be a primitive since `side_channel.is_none()` only when `res`
- // is a trait (and the side channel DefId is always an associated item).
- let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
- Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
- } else {
- // HACK(jynelson): `clean` expects the type, not the associated item
- // but the disambiguator logic expects the associated item.
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
- if let Some((kind, id)) = side_channel {
- self.kind_side_channel.set(Some((kind, id)));
- }
- Ok((res, Some(fragment)))
- };
- Some(result)
+
+ Some(Ok((res, Some(fragment))))
})
.unwrap_or_else(|| {
if ns == Namespace::ValueNS {
item_name: Symbol,
ns: Namespace,
module_id: DefId,
- ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> {
+ ) -> Option<(Res, ItemFragment)> {
let tcx = self.cx.tcx;
match root_res {
assoc_item.map(|item| {
let kind = item.kind;
- let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
- // HACK(jynelson): `clean` expects the type, not the associated item
- // but the disambiguator logic expects the associated item.
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
- (root_res, fragment, Some((kind.as_def_kind(), item.def_id)))
+ let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+ (root_res, fragment)
})
})
}
if let Some(item) = assoc_item {
let kind = item.kind;
- let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
- // HACK(jynelson): `clean` expects the type, not the associated item
- // but the disambiguator logic expects the associated item.
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
- return Some((root_res, fragment, Some((kind.as_def_kind(), item.def_id))));
+ let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+ return Some((root_res, fragment));
}
if ns != Namespace::ValueNS {
.non_enum_variant()
.fields
.iter()
- .find(|item| item.ident.name == item_name)?;
- Some((
- root_res,
- UrlFragment::StructField(field.ident.name),
- Some((DefKind::Field, field.did)),
- ))
+ .find(|item| item.ident(tcx).name == item_name)?;
+ Some((root_res, ItemFragment(FragmentKind::StructField, field.did)))
}
Res::Def(DefKind::Trait, did) => tcx
.associated_items(did)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
.map(|item| {
- let fragment = UrlFragment::from_assoc_item(
- item_name,
+ let fragment = ItemFragment::from_assoc_item(
+ item.def_id,
item.kind,
!item.defaultness.has_value(),
);
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
- (res, fragment, None)
+ (res, fragment)
}),
_ => None,
}
ns: Namespace,
path_str: &str,
module_id: DefId,
- extra_fragment: &Option<UrlFragment>,
+ extra_fragment: &Option<String>,
) -> Option<Res> {
// resolve() can't be used for macro namespace
let result = match ns {
- Namespace::MacroNS => self.resolve_macro(path_str, module_id).map_err(ErrorKind::from),
+ Namespace::MacroNS => self
+ .resolve_macro(path_str, module_id)
+ .map(|res| (res, None))
+ .map_err(ErrorKind::from),
Namespace::TypeNS | Namespace::ValueNS => {
- self.resolve(path_str, ns, module_id, extra_fragment).map(|(res, _)| res)
+ self.resolve(path_str, ns, module_id, extra_fragment)
}
};
let res = match result {
- Ok(res) => Some(res),
+ Ok((res, frag)) => {
+ if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag {
+ Some(Res::Def(self.cx.tcx.def_kind(id), id))
+ } else {
+ Some(res)
+ }
+ }
Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res),
Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
};
- self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
+ res
}
}
impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
fn visit_item(&mut self, item: &Item) {
- use rustc_middle::ty::DefIdTree;
-
let parent_node =
item.def_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did));
if parent_node.is_some() {
struct PreprocessingInfo {
path_str: String,
disambiguator: Option<Disambiguator>,
- extra_fragment: Option<UrlFragment>,
+ extra_fragment: Option<String>,
link_text: String,
}
Some(Ok(PreprocessingInfo {
path_str,
disambiguator,
- extra_fragment: extra_fragment.map(|frag| UrlFragment::UserWritten(frag.to_owned())),
+ extra_fragment: extra_fragment.map(|frag| frag.to_owned()),
link_text: link_text.to_owned(),
}))
}
};
let verify = |kind: DefKind, id: DefId| {
- let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
+ let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+ (self.cx.tcx.def_kind(id), id)
+ } else {
+ (kind, id)
+ };
debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
// Disallow e.g. linking to enums with `struct@`
match res {
Res::Primitive(prim) => {
- if let Some((kind, id)) = self.kind_side_channel.take() {
+ if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+ let kind = self.cx.tcx.def_kind(id);
+
// We're actually resolving an associated item of a primitive, so we need to
// verify the disambiguator (if any) matches the type of the associated item.
// This case should really follow the same flow as the `Res::Def` branch below,
&& item.def_id.is_local()
&& !self.cx.tcx.features().intra_doc_pointers
{
- let span = super::source_span_for_markdown_range(
- self.cx.tcx,
- dox,
- &ori_link.range,
- &item.attrs,
- )
- .unwrap_or_else(|| item.attr_span(self.cx.tcx));
-
- rustc_session::parse::feature_err(
- &self.cx.tcx.sess.parse_sess,
- sym::intra_doc_pointers,
- span,
- "linking to associated items of raw pointers is experimental",
- )
- .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does")
- .emit();
+ self.report_rawptr_assoc_feature_gate(dox, &ori_link, item);
}
} else {
match disambiguator {
}
}
+ fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) {
+ let span =
+ super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
+ .unwrap_or_else(|| item.attr_span(self.cx.tcx));
+ rustc_session::parse::feature_err(
+ &self.cx.tcx.sess.parse_sess,
+ sym::intra_doc_pointers,
+ span,
+ "linking to associated items of raw pointers is experimental",
+ )
+ .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does")
+ .emit();
+ }
+
fn resolve_with_disambiguator_cached(
&mut self,
key: ResolutionInfo,
if let Some(ref cached) = self.visited_links.get(&key) {
match cached {
Some(cached) => {
- self.kind_side_channel.set(cached.side_channel);
return Some(cached.res.clone());
}
None if cache_resolution_failure => return None,
// Cache only if resolved successfully - don't silence duplicate errors
if let Some(res) = res {
// Store result for the actual namespace
- self.visited_links.insert(
- key,
- Some(CachedLink {
- res: res.clone(),
- side_channel: self.kind_side_channel.clone().into_inner(),
- }),
- );
+ self.visited_links.insert(key, Some(CachedLink { res: res.clone() }));
Some(res)
} else {
let mut candidates = PerNS {
macro_ns: self
.resolve_macro(path_str, base_node)
- .map(|res| (res, extra_fragment.clone())),
+ .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
Ok(res) => {
debug!("got res in TypeNS: {:?}", res);
// Shouldn't happen but who knows?
Ok((res, Some(fragment)))
}
- (fragment, None) | (None, fragment) => Ok((res, fragment)),
+ (fragment, None) => Ok((res, fragment)),
+ (None, fragment) => {
+ Ok((res, fragment.map(UrlFragment::UserWritten)))
+ }
}
}
}
}
Some(MacroNS) => {
match self.resolve_macro(path_str, base_node) {
- Ok(res) => Some((res, extra_fragment.clone())),
+ Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
Err(mut kind) => {
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
for ns in [TypeNS, ValueNS] {
fn handle_variant(
cx: &DocContext<'_>,
res: Res,
- extra_fragment: &Option<UrlFragment>,
-) -> Result<(Res, Option<UrlFragment>), ErrorKind<'static>> {
- use rustc_middle::ty::DefIdTree;
-
- if extra_fragment.is_some() {
- // NOTE: `res` can never be a primitive since this function is only called when `tcx.def_kind(res) == DefKind::Variant`.
- return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
- }
+) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
cx.tcx
.parent(res.def_id(cx.tcx))
.map(|parent| {
let parent_def = Res::Def(DefKind::Enum, parent);
let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
- (parent_def, Some(UrlFragment::Variant(variant.ident.name)))
+ (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
})
.ok_or_else(|| ResolutionFailure::NoParentItem.into())
}
-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_field_def(&mut self, field: &ast::FieldDef) {
- self.load_links_in_attrs(&field.attrs, field.span);
- visit::walk_field_def(self, field)
+ 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)
+ }
+
+ // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
+ // then this will have to implement other visitor methods too.
}
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?
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();
}
});
- // `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);
--- /dev/null
+# Style for Templates
+
+This directory has templates in the [Tera templating language](teradoc), which is very
+similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc).
+
+[teradoc]: https://tera.netlify.app/docs/#templates
+[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/
+[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/
+[askamadoc]: https://docs.rs/askama/0.10.5/askama/
+
+We want our rendered output to have as little unnecessary whitespace as
+possible, so that pages load quickly. To achieve that we use Tera's
+[whitespace control] features. At the end of most lines, we put an empty comment
+tag with the whitespace control characters: `{#- -#}`. This causes all
+whitespace between the end of the line and the beginning of the next, including
+indentation, to be omitted on render. Sometimes we want to preserve a single
+space. In those cases we put the space at the end of the line, followed by
+`{# -#}`, which is a directive to remove following whitespace but not preceding.
+We also use the whitespace control characters in most instances of tags with
+control flow, for example `{%- if foo -%}`.
+
+[whitespace control]: https://tera.netlify.app/docs/#whitespace-control
+
+We want our templates to be readable, so we use indentation and newlines
+liberally. We indent by four spaces after opening an HTML tag _or_ a Tera
+tag. In most cases an HTML tag should be followed by a newline, but if the
+tag has simple contents and fits with its close tag on a single line, the
+contents don't necessarily need a new line.
+
+Tera templates support quite sophisticated control flow. To keep our templates
+simple and understandable, we use only a subset: `if` and `for`. In particular
+we avoid [assignments in the template logic](assignments) and [Tera
+macros](macros). This also may make things easier if we switch to a different
+Jinja-style template system, like Askama, in the future.
+
+[assignments]: https://tera.netlify.app/docs/#assignments
+[macros]: https://tera.netlify.app/docs/#macros
--- /dev/null
+<!DOCTYPE html> {#- -#}
+<html lang="en"> {#- -#}
+<head> {#- -#}
+ <meta charset="utf-8"> {#- -#}
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
+ <meta name="generator" content="rustdoc"> {#- -#}
+ <meta name="description" content="{{page.description}}"> {#- -#}
+ <meta name="keywords" content="{{page.keywords}}"> {#- -#}
+ <title>{{page.title}}</title> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Regular.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Medium.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
+ id="mainThemeStyle"> {#- -#}
+ {%- for theme in themes -%}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
+ {%- if theme == "light" -%}
+ id="themeStyle"
+ {%- else -%}
+ disabled
+ {%- endif -%}
+ >
+ {%- endfor -%}
+ <script id="default-settings" {# -#}
+ {% for (k, v) in layout.default_settings %}
+ data-{{k}}="{{v}}"
+ {%- endfor -%}
+ ></script> {#- -#}
+ <script src="{{static_root_path|safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
+ <script src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
+ <script defer src="{{static_root_path|safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+ {%- for script in page.static_extra_scripts -%}
+ <script defer src="{{static_root_path|safe}}{{script}}.js"></script> {#- -#}
+ {% endfor %}
+ {%- if layout.scrape_examples_extension -%}
+ <script defer src="{{page.root_path|safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+ {%- endif -%}
+ {%- for script in page.extra_scripts -%}
+ <script defer src="{{page.root_path|safe}}{{script}}.js"></script> {#- -#}
+ {% endfor %}
+ <noscript> {#- -#}
+ <link rel="stylesheet" {# -#}
+ href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
+ </noscript> {#- -#}
+ {%- if layout.css_file_extension.is_some() -%}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
+ {%- endif -%}
+ {%- if !layout.favicon.is_empty() -%}
+ <link rel="shortcut icon" href="{{layout.favicon}}"> {#- -#}
+ {%- else -%}
+ <link rel="alternate icon" type="image/png" {# -#}
+ href="{{static_root_path|safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
+ <link rel="alternate icon" type="image/png" {# -#}
+ href="{{static_root_path|safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
+ <link rel="icon" type="image/svg+xml" {# -#}
+ href="{{static_root_path|safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
+ {%- endif -%}
+ {{- layout.external_html.in_header|safe -}}
+</head> {#- -#}
+<body class="rustdoc {{page.css_class}}"> {#- -#}
+ <!--[if lte IE 11]> {#- -#}
+ <div class="warning"> {#- -#}
+ This old browser is unsupported and will most likely display funky things. {#- -#}
+ </div> {#- -#}
+ <![endif]--> {#- -#}
+ {{- layout.external_html.before_content|safe -}}
+ <nav class="sidebar"> {#- -#}
+ <div class="sidebar-menu" role="button">☰</div> {#- -#}
+ <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+ <div class="logo-container"> {#- -#}
+ {%- if !layout.logo.is_empty() %}
+ <img src="{{layout.logo}}" alt="logo"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
+ {%- endif -%}
+ </div>
+ </a> {#- -#}
+ {{- sidebar|safe -}}
+ </nav> {#- -#}
+ <main> {#- -#}
+ <div class="width-limiter"> {#- -#}
+ <div class="sub-container"> {#- -#}
+ <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+ {%- if !layout.logo.is_empty() %}
+ <img src="{{layout.logo}}" alt="logo"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
+ {%- endif -%}
+ </a> {#- -#}
+ <nav class="sub"> {#- -#}
+ <div class="theme-picker"> {#- -#}
+ <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
+ <img width="18" height="18" alt="Pick another theme!" {# -#}
+ src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
+ </button> {#- -#}
+ <div id="theme-choices" role="menu"></div> {#- -#}
+ </div> {#- -#}
+ <form class="search-form"> {#- -#}
+ <div class="search-container"> {#- -#}
+ <div>
+ <input {# -#}
+ class="search-input" {# -#}
+ name="search" {# -#}
+ autocomplete="off" {# -#}
+ spellcheck="false" {# -#}
+ placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+ type="search"> {#- -#}
+ </div> {#- -#}
+ <button type="button" id="help-button" title="help">?</button> {#- -#}
+ <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+ <img width="18" height="18" alt="Change settings" {# -#}
+ src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
+ </a> {#- -#}
+ </div> {#- -#}
+ </form> {#- -#}
+ </nav> {#- -#}
+ </div> {#- -#}
+ <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
+ <section id="search" class="content hidden"></section> {#- -#}
+ </div> {#- -#}
+ </main> {#- -#}
+ {{- layout.external_html.after_content|safe -}}
+ <div id="rustdoc-vars" {# -#}
+ data-root-path="{{page.root_path|safe}}" {# -#}
+ data-current-crate="{{layout.krate}}" {# -#}
+ data-themes="{{themes|join(",") }}" {# -#}
+ data-resource-suffix="{{page.resource_suffix}}" {# -#}
+ data-rustdoc-version="{{rustdoc_version}}" {# -#}
+ > {#- -#}
+ </div>
+</body> {#- -#}
+</html> {#- -#}
--- /dev/null
+<div class="main-heading">
+ <h1 class="fqn"> {#- -#}
+ <span class="in-band"> {#- -#}
+ {{-typ-}}
+ {#- The breadcrumbs of the item path, like std::string -#}
+ {%- for component in path_components -%}
+ <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
+ {%- endfor -%}
+ <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
+ <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
+ <img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
+ width="19" height="18" {# -#}
+ alt="Copy item path"> {#- -#}
+ </button> {#- -#}
+ </span> {#- -#}
+ </h1> {#- -#}
+ <span class="out-of-band"> {#- -#}
+ {% if !stability_since_raw.is_empty() %}
+ {{- stability_since_raw|safe -}} ·
+ {% endif %}
+ {%- match src_href -%}
+ {%- when Some with (href) -%}
+ <a class="srclink" href="{{href|safe}}" title="goto source code">source</a>
+ {%- else -%} ·
+ {%- endmatch -%}
+ <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
+ [<span class="inner">−</span>] {#- -#}
+ </a> {#- -#}
+ </span> {#- -#}
+</div>
// is declared but also a reexport of itself producing two exports of the same
// macro in the same module.
let mut inserted = FxHashSet::default();
- for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
+ for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) {
if let Res::Def(DefKind::Macro(_), def_id) = export.res {
if let Some(local_def_id) = def_id.as_local() {
if self.cx.tcx.has_attr(def_id, sym::macro_export) {
return;
}
- for item in self.tcx.item_children(def_id).iter() {
+ for item in self.tcx.module_children(def_id).iter() {
if let Some(def_id) = item.res.opt_def_id() {
if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index)
|| item.vis.is_public()
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5")]
+#[rustc_clean(except="hir_owner", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddUnsafeModifier {
#[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5")]
+#[rustc_clean(except="hir_owner", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddExternModifier {
#[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"})
-assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
-assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
+assert-css: (".srclink", {"color": "rgb(56, 115, 173)"})
+
+move-cursor-to: ".main-heading .srclink"
+assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"})
assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
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"
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
--- /dev/null
+// This test ensures that the correct style is applied to the rust logo in the sidebar.
+goto: file://|DOC_PATH|/test_docs/index.html
+
+// First we start with the dark theme.
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// Then with the ayu theme.
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// And finally with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "none"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+ ".rust-logo",
+ {"filter": "none"},
+)
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.
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.
goto: file://|DOC_PATH|/test_docs/index.html
assert-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
click: "#toggle-all-docs"
wait-for: 1000
// This is now collapsed so there shouldn't be the "open" attribute on details.
assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[+]")
click: "#toggle-all-docs"
wait-for: 1000
// Not collapsed anymore so the "open" attribute should be back.
assert-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
// This test ensures that the [src] link is present on traits items.
-// @has foo/trait.Iterator.html '//div[@id="method.zip"]//a[@class="srclink"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]//a[@class="srclink"]' "source"
pub use std::iter::Iterator;
#[macro_use]
extern crate external_macro_src;
-// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' '[src]'
+// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source'
// @has foo/struct.Foo.html
-// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' '[src]'
+// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source'
make_foo!();
pub struct Foo;
-// @has issue_16265_1/traits/index.html '[src]'
+// @has issue_16265_1/traits/index.html 'source'
pub mod traits {
impl PartialEq for super::Foo {
- fn eq(&self, _: &super::Foo) -> bool { true }
+ fn eq(&self, _: &super::Foo) -> bool {
+ true
+ }
}
}
-// @has issue_16265_2/index.html '[src]'
+// @has issue_16265_2/index.html 'source'
trait Y {}
-impl Y for Option<u32>{}
+impl Y for Option<u32> {}
extern crate issue_26606_macro;
// @has issue_26606/constant.FOO.html
-// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' '[src]'
+// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' 'source'
make_item!(FOO);
-<div class="docblock"><p>Hello world!
-Goodbye!
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
Hello again!</p>
</div>
\ No newline at end of file
--- /dev/null
+<div class="docblock"><p>Par 1</p>
+<p>Par 2</p>
+</div>
\ No newline at end of file
#[doc = "Goodbye!"]
/// Hello again!
pub struct S2;
+
+// @has 'foo/struct.S3.html'
+// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+/** Par 1
+*/ ///
+/// Par 2
+pub struct S3;
// @has foo/struct.Unsized.html
// @has - '//div[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
-// @!has - '//div[@id="impl-Sized"]//a[@class="srclink"]' '[src]'
+// @!has - '//div[@id="impl-Sized"]//a[@class="srclink"]' 'source'
// @has - '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
-// @!has - '//div[@id="impl-Sync"]//a[@class="srclink"]' '[src]'
+// @!has - '//div[@id="impl-Sync"]//a[@class="srclink"]' 'source'
// @has - '//div[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
-// @has - '//div[@id="impl-Any"]//a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Any"]//a[@class="srclink"]' 'source'
pub struct Unsized {
data: [u8],
}
pub struct Foo {
// @has - //pre "pub a: ()"
pub a: (),
- // @has - //pre "// some fields omitted"
+ // @has - //pre "/* private fields */"
// @!has - //pre "b: ()"
b: (),
// @!has - //pre "c: usize"
pub struct Bar {
// @has - //pre "pub a: ()"
pub a: (),
- // @!has - //pre "// some fields omitted"
+ // @!has - //pre "/* private fields */"
}
// @has structfields/enum.Qux.html
b: (),
// @has - //pre "c: usize"
c: usize,
- // @has - //pre "// some fields omitted"
+ // @has - //pre "/* private fields */"
},
}
-// @has structfields/struct.Baz.html //pre "pub struct Baz { /* fields omitted */ }"
+// @has structfields/struct.Baz.html //pre "pub struct Baz { /* private fields */ }"
pub struct Baz {
x: u8,
#[doc(hidden)]
#![crate_name = "foo"]
-// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' '[src]'
+// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source'
-// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' '[src]'
+// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source'
thread_local!(pub static FOO: bool = false);
// @has 'toggle_item_contents/struct.PrivStruct.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock item-decl"]' 'fields omitted'
+// @has - '//div[@class="docblock item-decl"]' '/* private fields */'
pub struct PrivStruct {
a: usize,
b: usize,
#![crate_name = "quix"]
pub trait Foo {
- // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' '[src]'
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source'
fn required();
- // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+ // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
fn provided() {}
}
pub struct Bar;
impl Foo for Bar {
- // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' '[src]'
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source'
fn required() {}
- // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+ // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
}
pub struct Baz;
impl Foo for Baz {
- // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' '[src]'
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source'
fn required() {}
- // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' '[src]'
+ // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source'
fn provided() {}
}
pub union U {
// @has - //pre "pub a: u8"
pub a: u8,
- // @has - //pre "// some fields omitted"
+ // @has - //pre "/* private fields */"
// @!has - //pre "b: u16"
b: u16,
}
--- /dev/null
+// edition:2018
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+#![allow(unused)]
+
+fn main() {
+ let x = test();
+}
+
+fn concat<const A: usize, const B: usize>(a: [f32; A], b: [f32; B]) -> [f32; A + B] {
+ todo!()
+}
+
+async fn reverse<const A: usize>(x: [f32; A]) -> [f32; A] {
+ todo!()
+}
+
+async fn test() {
+ let a = [0.0];
+ let b = [1.0, 2.0];
+ let ab = concat(a,b);
+ let ba = reverse(ab).await;
+ println!("{:?}", ba);
+}
--- /dev/null
+// 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() {}
--- /dev/null
+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
+
--- /dev/null
+// check-pass
+
+#![deny(unreachable_pub)]
+
+pub use self::m1::*;
+
+mod m1 {
+ pub use self::m2::*;
+
+ mod m2 {
+ pub struct Item1;
+ pub struct Item2;
+ }
+}
+
+
+pub use self::o1::{ Item42, Item24 };
+
+mod o1 {
+ pub use self::o2::{ Item42, Item24 };
+
+ mod o2 {
+ pub struct Item42;
+ pub struct Item24;
+ }
+}
+
+fn main() {}
--- /dev/null
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+
+pub trait Tr {
+ #[default_method_body_is_const]
+ fn a(&self) {}
+
+ #[default_method_body_is_const]
+ fn b(&self) {
+ ().a()
+ //~^ ERROR calls in constant functions are limited
+ }
+}
+
+impl Tr for () {}
+
+fn main() {}
--- /dev/null
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9
+ |
+LL | ().a()
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
LL | type bar = u64;
| ^^^^^^^^^^^^^^^ not a member of trait `Foo`
+error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo`
+ --> $DIR/impl-wrong-item-for-trait.rs:22:5
+ |
+LL | const MY_CONST: u32;
+ | -------------------- item in trait
+...
+LL | fn MY_CONST() {}
+ | ^^^^^^^^^^^^^^^^ does not match trait
+
error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
--> $DIR/impl-wrong-item-for-trait.rs:12:5
|
LL | const bar: u64 = 1;
| ^^^^^^^^^^^^^^^^^^^ does not match trait
+error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
+ --> $DIR/impl-wrong-item-for-trait.rs:30:5
+ |
+LL | fn bar(&self);
+ | -------------- item in trait
+...
+LL | type bar = u64;
+ | ^^^^^^^^^^^^^^^ does not match trait
+
error[E0046]: not all trait items implemented, missing: `bar`
--> $DIR/impl-wrong-item-for-trait.rs:10:1
|
LL | impl Foo for FooConstForMethod {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
-error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo`
- --> $DIR/impl-wrong-item-for-trait.rs:22:5
- |
-LL | const MY_CONST: u32;
- | -------------------- item in trait
-...
-LL | fn MY_CONST() {}
- | ^^^^^^^^^^^^^^^^ does not match trait
-
error[E0046]: not all trait items implemented, missing: `MY_CONST`
--> $DIR/impl-wrong-item-for-trait.rs:19:1
|
LL | impl Foo for FooMethodForConst {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `MY_CONST` in implementation
-error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
- --> $DIR/impl-wrong-item-for-trait.rs:30:5
- |
-LL | fn bar(&self);
- | -------------- item in trait
-...
-LL | type bar = u64;
- | ^^^^^^^^^^^^^^^ does not match trait
-
error[E0046]: not all trait items implemented, missing: `bar`
--> $DIR/impl-wrong-item-for-trait.rs:28:1
|
--- /dev/null
+// run-pass
+
+#![feature(ptr_metadata)]
+
+use std::alloc::Layout;
+use std::ptr::Pointee;
+
+trait Foo {
+ type Bar;
+}
+
+impl Foo for () {
+ type Bar = ();
+}
+
+struct Wrapper1<T: Foo>(<T as Foo>::Bar);
+struct Wrapper2<T: Foo>(<Wrapper1<T> as Pointee>::Metadata);
+
+fn main() {
+ let _: Wrapper2<()> = Wrapper2(());
+ let _ = Layout::new::<Wrapper2<()>>();
+}
LL | |x| x
| ^^^^^
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+ --> $DIR/issue-57611-trait-alias.rs:17:16
+ |
+LL | type Bar = impl Baz<Self, Self>;
+ | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r> Fn<(&'r X,)>`
+ found type `Fn<(&'static X,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-57611-trait-alias.rs:21:9
+ |
+LL | |x| x
+ | ^^^^^
+
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/issue-57611-trait-alias.rs:17:16
+ |
+LL | type Bar = impl Baz<Self, Self>;
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+ |
+ = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
+ = note: ...but it actually implements `FnOnce<(&'static X,)>`
+
+error: aborting due to 4 previous errors
+For more information about this error, try `rustc --explain E0308`.
let ext_with_default = !variant
.fields
.iter()
- .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.ident.name));
+ .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
let field_list = assigned_fields
.into_iter()
fields_def
.iter()
.find_map(|f_def| {
- if f_def.ident == field.ident
+ if f_def.ident(self.cx.tcx) == field.ident
{ Some(self.cx.tcx.type_of(f_def.did)) }
else { None }
});
then {
let mut def_order_map = FxHashMap::default();
for (idx, field) in variant.fields.iter().enumerate() {
- def_order_map.insert(field.ident.name, idx);
+ def_order_map.insert(field.name, idx);
}
if is_consistent_order(fields, &def_order_map) {
{
let mut current_and_super_traits = DefIdSet::default();
fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
+ let is_empty = sym!(is_empty);
let is_empty_method_found = current_and_super_traits
.iter()
- .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
+ .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
.any(|i| {
i.kind == ty::AssocKind::Fn
&& i.fn_has_self_parameter
- && i.ident.name == sym!(is_empty)
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
});
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
- if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" {
+ if item.kind == ty::AssocKind::Fn {
let sig = cx.tcx.fn_sig(item.def_id);
let ty = sig.skip_binder();
ty.inputs().len() == 1
/// Checks the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
+ let is_empty = sym!(is_empty);
cx.tcx.inherent_impls(id).iter().any(|imp| {
cx.tcx
.associated_items(*imp)
- .in_definition_order()
+ .filter_by_name_unhygienic(is_empty)
.any(|item| is_is_empty(cx, item))
})
}
let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
match ty.kind() {
ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
+ let is_empty = sym!(is_empty);
cx.tcx
.associated_items(principal.def_id())
- .in_definition_order()
+ .filter_by_name_unhygienic(is_empty)
.any(|item| is_is_empty(cx, item))
}),
ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
if let Res::Def(DefKind::Mod, id) = path.res;
if !id.is_local();
then {
- for kid in cx.tcx.item_children(id).iter() {
+ for kid in cx.tcx.module_children(id).iter() {
if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
let span = mac_attr.span;
let def_path = cx.tcx.def_path_str(mac_id);
s.push_str("::");
s
},
- variant.ident.name,
+ variant.name,
match variant.ctor_kind {
CtorKind::Fn if variant.fields.len() == 1 => "(_)",
CtorKind::Fn => "(..)",
use rustc_hir::{
BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
};
-use rustc_infer::traits::specialization_graph;
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, AssocKind, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;
// Lint a trait impl item only when the definition is a generic type,
// assuming an assoc const is not meant to be an interior mutable type.
if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
- if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id)
- .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id);
+ if let Some(of_assoc_item) = cx
+ .tcx
+ .associated_item(impl_item.def_id)
+ .trait_item_def_id;
if cx
.tcx
.layout_of(cx.tcx.param_env(of_trait_def_id).and(
// and, in that case, the definition is *not* generic.
cx.tcx.normalize_erasing_regions(
cx.tcx.param_env(of_trait_def_id),
- cx.tcx.type_of(of_assoc_item.def_id),
+ cx.tcx.type_of(of_assoc_item),
),
))
.is_err();
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
-use rustc_middle::ty::AssocKind;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
// trait, not in the impl of the trait.
let trait_method = cx
.tcx
- .associated_items(impl_trait_ref.def_id)
- .find_by_name_and_kind(cx.tcx, impl_item.ident, AssocKind::Fn, impl_trait_ref.def_id)
+ .associated_item(impl_item.def_id)
+ .trait_item_def_id
.expect("impl method matches a trait method");
- let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
+ let trait_method_sig = cx.tcx.fn_sig(trait_method);
let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
// `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
let lang_item_path = cx.get_def_path(*item_def_id);
if path_syms.starts_with(&lang_item_path) {
if let [item] = &path_syms[lang_item_path.len()..] {
- for child in cx.tcx.item_children(*item_def_id) {
+ for child in cx.tcx.module_children(*item_def_id) {
if child.ident.name == *item {
return true;
}
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
- for item in cx.tcx.item_children(def_id).iter() {
+ for item in cx.tcx.module_children(def_id).iter() {
if_chain! {
if let Res::Def(DefKind::Const, item_def_id) = item.res;
let ty = cx.tcx.type_of(item_def_id);
TraitItemKind, TraitRef, TyKind, UnOp, ArrayLen
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
-use rustc_middle::hir::exports::Export;
use rustc_middle::hir::map::Map;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::ty as rustc_ty;
}
};
}
- fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
- tcx.item_children(def_id)
- .iter()
- .find(|item| item.ident.name.as_str() == name)
+ fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<Res> {
+ match tcx.def_kind(def_id) {
+ DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
+ .module_children(def_id)
+ .iter()
+ .find(|item| item.ident.name.as_str() == name)
+ .map(|child| child.res.expect_non_local()),
+ DefKind::Impl => tcx
+ .associated_item_def_ids(def_id)
+ .iter()
+ .copied()
+ .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
+ .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
+ _ => None,
+ }
}
let (krate, first, path) = match *path {
let last = path
.iter()
.copied()
- // `get_def_path` seems to generate these empty segments for extern blocks.
- // We can just ignore them.
- .filter(|segment| !segment.is_empty())
// for each segment, find the child item
- .try_fold(first, |item, segment| {
- let def_id = item.res.def_id();
+ .try_fold(first, |res, segment| {
+ let def_id = res.def_id();
if let Some(item) = item_child_by_name(tcx, def_id, segment) {
Some(item)
- } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
+ } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
// it is not a child item so check inherent impl items
tcx.inherent_impls(def_id)
.iter()
None
}
});
- try_res!(last).res.expect_non_local()
+ try_res!(last).expect_non_local()
}
/// Convenience function to get the `DefId` of a trait by path.
}
}
-// issue #7015, ICE due to calling `item_children` with local `DefId`
+// issue #7015, ICE due to calling `module_children` with local `DefId`
#[macro_use]
use a as b;
}
}
-// issue #7015, ICE due to calling `item_children` with local `DefId`
+// issue #7015, ICE due to calling `module_children` with local `DefId`
#[macro_use]
use a as b;
-Subproject commit 824816c973a3fd0596ae3a9a38c6fb6299b913b8
+Subproject commit deb9bfd24648d50142ab29b810175837c4718885
-Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e
+Subproject commit 0f8c96c92689af8378dbe9f466c6bf15a3a27458
#![warn(unreachable_pub)]
#![recursion_limit = "256"]
#![allow(clippy::match_like_matches_macro)]
+#![allow(unreachable_pub)]
#[macro_use]
extern crate derive_new;
use std::path::Path;
-fn is_edition_2018(mut line: &str) -> bool {
- line = line.trim();
- line == "edition = \"2018\""
-}
-
fn is_edition_2021(mut line: &str) -> bool {
line = line.trim();
line == "edition = \"2021\""
return;
}
- // Not all library crates are ready to migrate to 2021.
- if file.components().any(|c| c.as_os_str() == "library")
- && file.components().all(|c| c.as_os_str() != "std")
- {
- let has = contents.lines().any(is_edition_2018);
- if !has {
- tidy_error!(
- bad,
- "{} doesn't have `edition = \"2018\"` on a separate line",
- file.display()
- );
- }
- } else {
- let is_2021 = contents.lines().any(is_edition_2021);
- if !is_2021 {
- tidy_error!(
- bad,
- "{} doesn't have `edition = \"2021\"` on a separate line",
- file.display()
- );
- }
+ let is_2021 = contents.lines().any(is_edition_2021);
+ if !is_2021 {
+ tidy_error!(
+ bad,
+ "{} doesn't have `edition = \"2021\"` on a separate line",
+ file.display()
+ );
}
},
);